二分搜索(折半搜索),lower_bound,upper_bound
二分查找
二分查找也稱折半查找(Binary Search),它是一種效率較高的查找方法。但是,折半查找要求線性表必須采用順序存儲結構,而且表中元素按關鍵字有序排列。
查找過程
首先,假設表中元素是按升序排列,將表中間位置記錄的關鍵字與查找關鍵字比較,如果兩者相等,則查找成功;否則利用中間位置記錄將表分成前、后兩個子表,如果中間位置記錄的關鍵字大于查找關鍵字,則進一步查找前一子表,否則進一步查找后一子表。重復以上過程,直到找到滿足條件的記錄,使查找成功,或直到子表不存在為止,此時查找不成功。
算法要求
1.必須采用順序存儲結構。
2.必須按關鍵字大小有序排列。
算法復雜度
二分查找的基本思想是將n個元素分成大致相等的兩部分,取a[n/2]與x做比較,如果x=a[n/2],則找到x,算法中止;如果x<a[n/2],則只要在數組a的左半部分繼續搜索x,如果x>a[n/2],則只要在數組a的右半部搜索x.
時間復雜度即是while循環的次數。
總共有n個元素,
漸漸跟下去就是n,n/2,n/4,…n/2^k(接下來操作元素的剩余個數),其中k就是循環的次數
由于你n/2^k取整后>=1
即令n/2^k=1
可得k=log2n,(是以2為底,n的對數)
所以時間復雜度可以表示O(h)=O(log2n)
二分查找圖示
二分查找模板
①查找精確值,從一個有序數組中找到一個符合要求的精確值(如猜數游戲)。如查找值為Key的元素下標,不存在返回-1。
//這里是left<=right。 //考慮這種情況:如果最后剩下A[i]和A[i+1](這也是最容易導致導致死循環的情況)首先mid = i, //如果A[mid] < key,那么left = mid+1 = i +1,如果是小于號,則A[i + 1]不會被檢查,導致錯誤 int left = 1,right = n; while(left <= right) {//這里left和right代表的是數組下標,所有沒有必要改寫成mid = left + (right - left)/2;//因為當代表數組下標的時候,在數值越界之前,內存可能就已經越界了//如果left和right代表的是一個整數,就有必要使用后面一種寫法防止整數越界int mid = (left + right) / 2;if(A[mid] == key)return mid;else if(A[mid] > key)//這里因為mid不可能是答案了,所以搜索范圍都需要將mid排除right = mid - 1;elseleft = mid + 1; } return -1;②查找大于等于/大于key的第一個元素。
int left = 1,right = n; while(left < right) {//這里不需要加1。我們考慮如下的情況,最后只剩下A[i],A[i + 1]。//首先mid = i,如果A[mid] > key,那么right = left = i,跳出循環,如果A[mid] < key,left = right = i + 1跳出循環,所有不會死循環。int mid = (left + right) / 2;if(A[mid] > key)//如果要求大于等于可以加上等于,也可以是check(A[mid])right = mid;//因為找的是大于key的第一個元素,那么比A[mid]大的元素肯定不是第一個大于key的元素,因為A[mid]已經大于key了,所以把mid+1到后面的排除elseleft = mid + 1;//如果A[mid]小于key的話,那么A[mid]以及比A[mid]小的數都需要排除,因為他們都小于key。不可能是第一個大于等于key的元素, }③查找小于等于/小于key的最后一個元素。
int left = 1, right = n; while(left < right) {//這里mid = (left + right + 1) / 2;//考慮如下一種情況,最后只剩下A[i],A[i + 1],如果不加1,那么mid = i,如果A[mid] < key,執行更新操作后,left = mid,right = mid + 1,就會是死循環。//加上1后,mid = i + 1,如果A[mid] < key,那么left = right = mid + 1,跳出循環。如果A[mid] > key,left = mid = i,跳出循環。int mid = (left + right + 1) / 2;if(A[mid] < key)left = mid;//如果A[mid]小于key,說明比A[mid]更小的數肯定不是小于key的最大的元素了,所以要排除mid之前的所有元素elseright = mid - 1;//如果A[mid]大于key,那么說明A[mid]以及比A[mid]還要大的數都不可能小于key,所以排除A[mid]及其之后的元素。 }STL二分模板
①lower_bound。找到大于等于某個數的第一個位置。
頭文件:algorithm。
對象:有序數組或容器。
示例代碼:
也可以對不定長數組vector進行二分搜索。
#include<iostream> #include<algorithm> #include<vector> using namespace std;int main() {vector<int> A;A.push_back(1); A.push_back(2); A.push_back(3); A.push_back(4); A.push_back(5); A.push_back(7); A.push_back(8); A.push_back(9); int pos = lower_bound(A.begin() , A.end() , 6)-A.begin();//A.begin()代表的是A的迭代器cout << pos << endl;return 0; }②upper_bound。找到大于某個數的位置。
基本用法和lower_bound一樣的。
STL中的這兩個二分函數,是應用比較廣泛的,理解他們的用處之后再去多加以應用。
努力加油a啊,(o)/~
總結
以上是生活随笔為你收集整理的二分搜索(折半搜索),lower_bound,upper_bound的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图的广度优先搜索(bfs)以及深度优先搜
- 下一篇: 数据结构之线段树入门(单点更新区间查询)