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