1. 程式人生 > >對標準庫stdlib.h中二分查詢的理解

對標準庫stdlib.h中二分查詢的理解

前幾天面試的時候遇到了這個問題 ,標準庫下提供的二分查詢改錯,當時沒有改出來,寫得不好,回來查了下,這個函式的原型是:

/* 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]);