對標準庫stdlib.h中二分查詢的理解
阿新 • • 發佈:2018-11-02
前幾天面試的時候遇到了這個問題 ,標準庫下提供的二分查詢改錯,當時沒有改出來,寫得不好,回來查了下,這個函式的原型是:
/* bsearch() and qsort() are declared both here, in <stdlib.h>, and in * non-ANSI header <search.h>; we reproduce these declarations in both, * with no attempt to guard them, so the compiler may verify that they * are consistent, if both headers are included. */ _CRTIMP __cdecl void *bsearch (const void *, const void *, size_t, size_t, int (*)(const void *, const void *));
接受任何型別的資料進行二分查詢,自己一開始糾結在於返回值問題,一直以來自己以為的查詢侷限於,陣列,返回的應該是一個下標,查到的元素在陣列中的第幾個。這是自己一點的誤區,應該聯想記憶體一起思考。
回來看了下bsearch原始碼,發現不然,標準庫提供的二分查詢,返回的是記憶體地址,而不是一個下標更不是一個值。
返回的是一個記憶體地址,這樣子這個二分查詢是非常強大的,可以對一段連續記憶體進行查詢,前提這段記憶體的資料是有序的,。
看一下標準庫的二分查詢實現程式碼。
/* Perform a binary search for KEY in BASE which has NMEMB elements of SIZE bytes each. The comparisons are done by (*COMPAR)(). */ void * bsearch (const void *key, const void *base, size_t nmemb, size_t size, int (*compar) (const void *, const void *)) { size_t l, u, idx; //這裡的idx就是查詢的位置 但返回的並不是idx idx只是用來計算距離首地址有多少個元素 const void *p; // 這個p代表的是 idx處的值 int comparison; // 初始化左右邊界 l = 0; u = nmemb; while (l < u) { // 取左右區間的中點 idx = (l + u) / 2; // base + (idx * size)這個是計算idx處的記憶體地址地址 傳遞給compar函式進行值比較 p = (void *) (((const char *) base) + (idx * size)); comparison = (*compar) (key, p); if (comparison < 0) // 右邊界更新為當前中點 u = idx; else if (comparison > 0) // 左邊界右移動一個 l = idx + 1; else return (void *) p; } return NULL; }
關於對標準庫的二分查詢,要從記憶體角度理解,就如同void*型別的qsort一樣。不單單停留在值的層次,是從記憶體的角度思考出發。
而對這個返回的記憶體地址,和首地址做差,就能得到偏移的位元組數,進一步可以得到下標
index = (pes - (void *)array) / sizeof(array[0]);