【经典算法——查找】二分查找
二分查找又称为折半查找,仅适用于事先已经排好序的顺序表。其查找的基本思路:首先将给定值K,与表中中间位置元素的关键字比较,若相等,返回该元素的存储位置;若不等,这所需查找的元素只能在中间数据以外的前半部分或后半部分中。然后在缩小的范围中继续进行同样的查找。如此反复直到找到为止。算法如下:
1 template<typename T> 2 int BinarySearch(vector<T> &data, T key) { 3 int low = 0, high = data.size() - 1; 4 while (low <= high) { 5 int mid = low + (high - low) / 2; 6 if (data[mid] == key) { 7 return mid; 8 } else if (data[mid] > key) { 9 high = mid - 1; 10 } else { 11 low = mid + 1; 12 } 13 } 14 15 return -1; 16 }
因为二分查找需要方便地定位查找区域,所以适合二分查找的存储结构必须具有随机存储的特性。因此,该查找方法仅适合于线性表的顺序存储结构,不适合链式存储结构,且要求元素按关键字有序排列。
判定树:
二分查找的过程可以用下图表示,称为判定树。树中每个圆形节点表示一个纪录,节点中的值表示为该记录的关键字值:树中最下面叶节点都是方形的,它表示查找不成功的情况。从判定树中可以看出,查找成功时查找的查找长度为从根节点到目的节点的路径上的节点数,而查找不成功时的查找长度为从根节点到对应失败节点的父节点的父节点路径上的节点数;每个节点值均大于其左子节点值,且均小于右子节点值。若有序序列有n个元素,这对应的判定树有n个圆形的非叶节点和n+1个方形的叶节点。
上图中,n个圆形节点(代表有序序列有n个元素)构成的树的深度与n个节点完全二叉树的深度(高度)相等,均为⌊log2n⌋+1或⌈log2(n+1)⌉
二分查找的时间复杂度为O(log2N),比顺序查找的效率高。
由上述分析可知,用二分查找到给定值或查找失败的比较次数最多不会超过树的高度。查找成功与不成功,最坏的情况下,都需要比较⌊log2n⌋+1次。
二分查找的优点和缺点
虽然二分查找的效率高,但是要将表按关键字排序。而排序本身是一种很费时的运算。既使采用高效率的排序方法也要花费O(nlgn)的时间。
二分查找只适用顺序存储结构。为保持表的有序性,在顺序结构里插入和删除都必须移动大量的结点。因此,二分查找特别适用于那种一经建立就很少改动、而又经常需要查找的线性表。
对那些查找少而又经常需要改动的线性表,可采用链表作存储结构,进行顺序查找。链表上无法实现二分查找。
相关题目:
1. [LeetCode] Search in Rotated Array
2. [LeetCode] Search in Rotated Array II
4.《剑指offer》面试题3、面试题8
相关资料:
1.http://www.zhihu.com/question/22422613
2.http://www.cppblog.com/converse/archive/2009/10/05/97905.html
3.http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=binarySearch
4.http://www.cnblogs.com/bhlsheji/p/4211826.html
参考资料:
1.《王道程序员求职宝典》
2. http://student.zjzk.cn/course_ware/data_structure/web/chazhao/chazhao9.2.2.1.htm