C语言二分查找法实现与细节
2016-05-16 17:42
337 查看
刚学C的时候没过多久就接触到这种算法,总的来说这个算法并不难。时隔好久,今天看了下书,加深了一些理解,谨记此文,用于回顾及梳理知识。
如要求:
编写一个函数,对一个已排序的整数表执行二分查找。函数的输入包括一个指向表头的指针,表中的元素个数,以及待查找的数值。函数的输出是一个指向满足查找要求的元素的指针,当未查找到要求的数值时,输出一个NULL指针。
下图显示大致搜索过程:
假定x是要搜索的元素,k表示要搜索的元素的下标,n是表中的元素个数。任何时候假定lo和hi是不对称边界的两头。也就是说,lo <= k < hi。
如果lo与hi相等,此时可能范围已缩为空,所以可以判定x不在表中。如果lo小于hi,那么可能范围中至少存在一个元素。假定mid为可能范围的中值,然后比较x与表中下标为mid的元素。如果x比该元素小,那么mid就是位于可能范围以外的最小下标,因此可以设置hi = mid。如果x比该元素大,那么mid + 1就是位于新的已缩减的可能范围以内的最小下标,因此可以设置lo = mid + 1。如果x与该元素相等,则完成搜索。
对于假定mid为可能范围的中值。存在这样一个问题:是否可以设置mid = (hi + lo) / 2; 这样设置会不会带来一些问题?
分析:如果hi与lo相隔较远这样做显然没问题,但是如果相隔太近又是怎么样情况?
对于hi等于lo的情况不用考虑,因为已经判断出x的可能范围为空,所以甚至不需要设置mid。而当hi = lo + 2时,hi + lo = lo * 2 + 2,这是个偶数,因此 (hi + lo) / 2 = lo + 1。当hi = lo + 1时,可能范围中的唯一元素就是lo,由于hi + lo恒为正数,(hi + lo) / 2肯定会等于lo,因为在这种情况下整数除法会被截断处理,即(hi + lo) / 2 = (2lo + 1) / 2,结果就为lo。
所以根据以上分析,mid = (hi + lo) / 2; 没有问题。
具体代码如下:
值得一提的是,int mid = (lo + hi) / 2;可以改写为int mid = (lo + hi) >> 1;这样会提高程序的运行速度,将上面的程序中一些寻址运算替换,在很多机器上下标运算都要比指针运算慢。改写后的程序如下:
如要求:
编写一个函数,对一个已排序的整数表执行二分查找。函数的输入包括一个指向表头的指针,表中的元素个数,以及待查找的数值。函数的输出是一个指向满足查找要求的元素的指针,当未查找到要求的数值时,输出一个NULL指针。
下图显示大致搜索过程:
假定x是要搜索的元素,k表示要搜索的元素的下标,n是表中的元素个数。任何时候假定lo和hi是不对称边界的两头。也就是说,lo <= k < hi。
如果lo与hi相等,此时可能范围已缩为空,所以可以判定x不在表中。如果lo小于hi,那么可能范围中至少存在一个元素。假定mid为可能范围的中值,然后比较x与表中下标为mid的元素。如果x比该元素小,那么mid就是位于可能范围以外的最小下标,因此可以设置hi = mid。如果x比该元素大,那么mid + 1就是位于新的已缩减的可能范围以内的最小下标,因此可以设置lo = mid + 1。如果x与该元素相等,则完成搜索。
对于假定mid为可能范围的中值。存在这样一个问题:是否可以设置mid = (hi + lo) / 2; 这样设置会不会带来一些问题?
分析:如果hi与lo相隔较远这样做显然没问题,但是如果相隔太近又是怎么样情况?
对于hi等于lo的情况不用考虑,因为已经判断出x的可能范围为空,所以甚至不需要设置mid。而当hi = lo + 2时,hi + lo = lo * 2 + 2,这是个偶数,因此 (hi + lo) / 2 = lo + 1。当hi = lo + 1时,可能范围中的唯一元素就是lo,由于hi + lo恒为正数,(hi + lo) / 2肯定会等于lo,因为在这种情况下整数除法会被截断处理,即(hi + lo) / 2 = (2lo + 1) / 2,结果就为lo。
所以根据以上分析,mid = (hi + lo) / 2; 没有问题。
具体代码如下:
/* 数组实现 */ int *bsearch(int *t, int n, int x) { int lo = 0, hi = n; while (lo < hi) { int mid = (lo + hi) / 2; if (x < t[mid]) hi = mid; else if (x > t[mid]) lo = mid + 1; else return t + mid; } return NULL; }
值得一提的是,int mid = (lo + hi) / 2;可以改写为int mid = (lo + hi) >> 1;这样会提高程序的运行速度,将上面的程序中一些寻址运算替换,在很多机器上下标运算都要比指针运算慢。改写后的程序如下:
/* 指针实现 */ int *bsearch(int *t, int n, int x) { int *lo = t, *hi = t + n; while (lo < hi) { /* int *mid = (lo + hi) / 2; 注意!这种写法是非法的,它将两个指针相加 */ int *mid = (lo + (hi - lo)) >> 1; /* 正确方法 */ if (x < *mid) hi = mid; else if (x > *mid) lo = mid + 1; else return mid; } return NULL; }
相关文章推荐
- inline!C++内联
- C/C++中nth_element函数
- C++中的const函数与const_cast的矛盾
- PAT (Basic Level) Practise (中文)1050. 螺旋矩阵(25)
- CRC32校验算法C语言版(查表法)
- stdint--ISO C99: 7.18 Integer typesC语言扩展类型
- C语言的数据类型转换
- JS下打印三角形(其实和C语言一样的套路)
- 简化版的SHA1算法C语言版
- c语言:图的邻接矩阵的建立与广度优先搜索实现
- Template Method模式理解
- opencl:c++接口(cl.hpp)利用cl::LocalSpaceArg设置__local 参数
- 详解一道C++笔试题,考察重载、覆盖、多态
- C++利用链栈实现表达式求值
- c语言libcurl库的异步用法
- c++ 单例模式下的实例自动销毁(单例自动回收器)
- C++回收回收
- C语言中关键字const、static、volatile的用法分析
- C++对象的内存分布和虚函数表
- R - Milking Time——POJ C语言实现