对标准库stdlib.h中二分查找的理解

前几天面试的时候遇到了这个问题 ,标准库下提供的二分查找改错,当时没有改出来,写得不好,回来查了下,这个函数的原型是:

/* bsearch() and qsort() are declared both here, in , and in
 * non-ANSI header ; 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]);

 

你可能感兴趣的:(编程收获)