二分查找(c & c++)
2015-08-07 11:42
281 查看
typedef int ElemType;
C版本
【递归版本】int binSearch2(ElemType List[] ,int x,int head,int tail){ //递归版本 while(head<=tail){ int mid=(head+tail)/2; if(List[mid]==x){ return mid; } else if(List[mid]>x){ return binSearch2(List,x,head,mid-1); } else{ return binSearch2(List,x,mid+1,tail); } } return -1; }
【迭代版本】
int binSearch(ElemType List[] ,int x,int head,int tail){ //循环版本 while(head<=tail){ int mid=(head+tail)/2; if(List[mid]==x) return mid; else if(List[mid]>x){ //注意别写反 tail=mid-1; } else{ head=mid+1; } } return -1; }
C++版本
上面是之前C语言的版本,这里用C++再来实现,有三个版本,顺便进行效率的分析。【版本A】
template <typename T> static int Binsearcha(T *arr ,int lo,int hi,T x){ while(lo < hi){ int mid = (lo + hi) >>1; if(x <arr[mid]) hi = mid; else if (arr[mid] < x) lo = mid + 1; else return mid; } return -1; //查找失败 }先看是否在左边,再看是否在右边,都不是就找到了。可以看出每次循环,如果x小于mid位置的元素 只需要一次比较 , 而当mid位置的元素小于x则需要两次比较,这样就造成了效率的分差,即:当所找的元素在左边效率高,在右边效率低。经过课上的分析得出,版本A的算法平均效率为Θ(1.50 log(n));
怎么优化呢? 左边查找效率高,右边效率低,那么我们取mid的时候不在中间取,而是多往hi靠近。也就是说增长左边的区间,缩短右边的区间,这样就能尽量的“平均”分配。 经过证明这个比例的最优版本就是黄金分割 0.618: 0.382; 也就是斐波那契相邻两个数的比例。
所以这个优化也可以称作是斐波那契查找。平均效率Θ(1.44 log(n)); 是这种方法的最优效率。
因为版本B,C的二分查找效率更高 所以这里也不给出斐波那契查找的算法实现了。
版本A之所以效率低,无非是左右两边查找效率不同所致,其实我们可以让他们变得相同。
【版本 B】
template <typename T> static int Binsearchb(T *arr ,int lo,int hi,T x){ while(1 < hi - lo){ int mid = (lo + hi) >>1; if(x <arr[mid]) hi = mid; else lo = mid; } return (x == arr[lo]) ? lo : -1; }
只用if else 每次将区间分成两部分,取其一即可。这样无论是大还是小都只需比较1次。然后不断压缩区间。
因为STL中区间都是左闭又开的[ a , b ) ,所以最终hi - lo == 1 终止循环即可, lo 所在位置就是所找的元素。
【版本C】
template <typename T> static int Binsearchc(T *arr ,int lo,int hi,T x){ while(lo < hi){ int mid = (lo + hi) >>1; if(x <arr[mid]) hi = mid; else lo = mid+1; } return --lo; }
为了实现其他接口(例如 insert)的调用,我们希望这个函数返回的是 在arr中不大于x最后一个位置,因此在分割区间的时候我们我们尽量用lo去逼近所要查找的值
最终结果无非是两个,①lo刚好等于要找的元素,②找到比要查找元素大的那个数(即序列中没有所找的元素x),然后返回 -- lo , 也就是(在arr中不大于x的最后一个位置);
可以看出在最好的情况版本A的效率是O(1) , 平均效率 Θ(1.50 log(n));
版本B和C的效率一直是 Θ(log(n)); 显然后者要更好。
相关文章推荐
- 字典树的基本知识及使用C语言的相关实现
- 利用ffmpeg将H264流 解码为RGB 分类: VC++ ffmpeg-SDL-VLC-Live555 2015-08-07 11:39 155人阅读 评论(0) 收藏
- 双缓冲解决VC++绘图时屏幕闪烁
- C++:overload, override和overwrite
- 详解次小生成树以及相关的C++求解方法
- c语言》查找法-数组下标
- 面试笔试(C++部分)
- C++_Switch Statement
- Sublime 在win上搭建C++环境
- C++抽象机制之二:运算符重载
- HDOJ 2024 C语言合法标识符(水)
- C++ Vector
- C++ AMP 介绍(两)
- c++ STL中的set容器
- C++模板元编程
- c++子类和父类成员函数重名
- c语言》排序法
- #编码风格#C++ Programming Style Guidelines
- VC++开发中遇到的一些问题整理
- 怎样从一个DLL中导出一个C++类