本博客是我在做题和看书遇到各种情况的总结。
参考了书,邓俊辉老师编写的《数据结构(C++语言版)(第3版)》,同时还有网友的总结(以下会给出相应的链接)。
一、查找等于目标元素的位置(若是多个,只要求找到即可)
1 /二分查找的主体 2 int binarySearch(int A[], int n, int target) 3 { 4 int lo = 0, hi = n; //n为数组的A元素的个数 5 6 while (lo < hi) 7 { 8 int mid = lo + (hi - lo)/2; 9 if (A[mid] == target) 10 return mid; 11 else if (target < A[mid]) 12 hi = mid; 13 else 14 lo = mid + 1; 15 } 16 return -1; 17 }
这里关于右边界hi的取值值得注意的有几点:
1)在while循环外面的hi=n,说明是前开后闭型([0,n) ),那么在while循环中的hi的取值应构成前开后闭型([ lo,mid )),此时while循环的条件为lo<hi ;
2)在while循环外面的hi=n-1,说明是前开后闭型([0,n-1]),那么在while循环中的hi的取值应构成前开后闭型([ lo,mid-1]),此时while循环的条件为lo<=hi ;
这里不是说,其他情况下的使用,就不能使用,只是有时候会出错。
二、查找重复元素的第一个值的下标,若是没有重复元素则返回第一个不小于目标值的下标。
1 //二分查找的主体 2 int binarySearch(int A[], int n, int target) 3 { 4 int lo = 0, hi = n; 5 6 while (lo < hi) 7 { 8 int mid = lo + (hi - lo)/2; 9 10 if (A[mid] < target) 11 lo = mid + 1; 12 else 13 hi = mid; 14 } 15 return hi; 16 }
注:这里的hi值也可以像一种那样变化,要对应的变化。只不过这样改变以后,在不存在目标值的情况下,返回的是第一个小于目标值(从目标值往左数)的下标。
三、查找重复元素的最后一个下标,或者不存在目标值时,第一个小于目标值的下标。这种情况,邓老师书上有严格的证明。
1 //二分查找的主体 2 int binarySearch(int A[], int n, int target) 3 { 4 int lo = 0, hi = n; 5 6 while (lo < hi) 7 { 8 int mid = lo + (hi - lo)/2; 9 10 if (A[mid] <= target) 11 lo = mid + 1; 12 else 13 hi = mid; 14 } 15 return --lo; //必须减减 16 }
注意:第二种和第三种的区别在于if条件判断语句的差别,和返回值的区别,
四、将二、三结合就可以求出存在多个目标值时,目标值所在的区间。详情见search for a range。
版本一的进化版是斐波那契查找,这和二分查找的主要区别在于中间点mid是使用斐波那契进行选择的,版本三的各分支的平均查更好些,详情请见参考书。
总结
针对二分查找,值得注意的是区间的选取(见第一种情况下的说明);要是求目标值给定条件下(第一个或最后一个)下的下标,可以通过变化while循环中的if条件内的等号所在来实现。
下面给出第三种情况下测试程序,第一、二中可以通过变化数组A所含的值来实现。
1 #include<iostream> 2 #include<vector> 3 4 using namespace std; 5 6 int binarySearch(int A[], int n, int target); 7 8 int main() 9 { 10 int A[] = { 0,1,2,3,4,4,4,4,5,6,7,8,9 }; 11 int target = 4; 12 int res = binarySearch(A, 13, target); 13 cout << "目标值的下标是:" << res << endl; 14 return 0; 15 } 16 17 //二分查找的主体 18 int binarySearch(int A[], int n, int target) 19 { 20 int lo = 0, hi = n; 21 22 while (lo < hi) 23 { 24 int mid = lo + (hi - lo)/2; 25 26 if (A[mid] <= target) 27 lo = mid + 1; 28 else 29 hi = mid; 30 } 31 return --lo; //必须减减 32 } 33 34 35 /* 36 int A[] = { 0,1,2,3,4,4,4,4,5,6,7,8,9 },target=4时,返回值为7 37 int A[] = { 0,1,2,4,4,4,4,5,6,7,8,9 },target=3时,返回值为2 38 int A[] = { 0,1,2,4,4,4,4,5,6,7,8,9 },target=3,返回lo时,返回值为3 39 */
若是各位看官发现什么问题,多多留言哈,共同进步~
参考:
http://www.61mon.com/index.php/archives/187/
http://blog.csdn.net/sunmenggmail/article/details/7540970
http://www.cnblogs.com/luoxn28/p/5767571.html
http://www.cnblogs.com/grandyang/p/6854825.html