二分法查找的一种写法,高逼格是指她有亮点,提供了一种想法和思路,只要脑子转得快,代码才有更优质的写法。
函数功能
二分法遍历结构base0
以查找key
,如果找到,返回与key
相邻的下一个元素。否则返回base0
的第一个元素。
函数参数
- const void *key:需要查找的元素
- const void *base0:指向源数据保存的空间
- size_t nelements:源数据的元素个数
- size_t element_size:源数据的每个元素的空间大小
- int (*compar)(const void *, const void *):比较函数指针
灵活度、通用性很高。通过自己传入的base0
和compar
封装出自己代码合适的接口。
函数定义
核心为中间for循环
void *
bsearch(const void *key, const void *base0, size_t nelements,
size_t element_size, int (*compar)(const void *, const void *))
{
const char *base = base0;
size_t lim;
int cmp = 0;
const void *p = NULL, *pnext;
for (lim = nelements; lim != 0; lim >>= 1)
{
p = base + (lim >> 1) * element_size;
cmp = (*compar)(key, p);
if (cmp == 0)
break;
if (cmp > 0)
{
lim--;
base = (const char *)p + element_size;
}
}
if ( lim == 0 && cmp < 0 )
return (void *)p;
pnext = (const char *)p + element_size;
if ( (const char *)pnext < (const char *)base0 + (nelements * element_size) )
return (void *)pnext;
else
return NULL;
}
函数解析
for循环从数组尾部由变量lim控制,向数组头部遍历。循环变量每次右移一位。这也是函数的亮点之一:
lim >>= 1 <=等价于=> lim /= 2
循环体内,指针p将指向区间的中间元素,指针base指向二分的左边界。
compar函数的设计为,如果key>p,则返回>0。因此当返回>0时,说明key在p的右边。此时修改base(也就是右边界)到当前p+1的位置。lim用来控制当前区间数量。