二分搜索及其扩展(循环递增数组的搜索)
生活随笔
收集整理的這篇文章主要介紹了
二分搜索及其扩展(循环递增数组的搜索)
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
二分搜索需要注意開閉區(qū)間的問題,限制條件和邊界要保持配對:low<=high , low = mid +1? ,high = mid-1。
二分搜索的模板如下:
// 二分搜索 int BinarySearch(int *num, int key, int low, int high) {int mid ;while(low <= high) //切記:條件是 <= ,很多次都不小心寫成了 < ,導(dǎo)致了N多WA{mid = (low + high)>>1;if(num[mid] == key)return mid;else if(num[mid] < key)low = mid + 1;elsehigh = mid -1;}return low; //查找不成功時(shí),返回應(yīng)該插入的位置,或者直接返回-1,表示查找失敗也是可以的 } ????? 二分搜索的擴(kuò)展:對已排好序的數(shù)組A,一般來說可用二分查找 可以很快找到。現(xiàn)有一特殊數(shù)組A[],它是循環(huán)遞增的,如A[]={ 17 19 20 25 1 4 7 9},試在這樣的數(shù)組中找一元素x,看看是否存在。請寫出你的算法,必要時(shí)可寫偽代碼,并分析其空間、時(shí)間復(fù)雜度。
????? 對于循環(huán)有序的數(shù)組,它是循環(huán)遞增的,例如:A[]={ 17 19 20 25 1 4 7 9},也可以使用二分搜索:每次將數(shù)組分為2部分,一個(gè)是單調(diào)遞增的,一個(gè)是循環(huán)遞增的。如果是單調(diào)遞增的話直接使用樸素的二分搜索,如果是循環(huán)遞增的話繼續(xù)使用特殊二分搜索下去。
思路分析:
????? 在一個(gè)數(shù)組中檢索一個(gè)元素,最普通的算法就是時(shí)間復(fù)雜度為O(n)的順序檢索。要降低時(shí)間復(fù)雜度,并結(jié)合循環(huán)遞增數(shù)組的元素已有一定程度順序的性質(zhì),很容易想到二分查找。
????? 我最初的想法是:樸素的二分查找在是下標(biāo)區(qū)間[0 n-1]內(nèi)進(jìn)行二分,那么利用循環(huán)遞增的性質(zhì),我們可以在數(shù)組的有效下標(biāo)區(qū)間[0 n-1]的一個(gè)偏移區(qū)間[r+1 n+r-1]里進(jìn)行二分(其中r是上述循環(huán)遞增數(shù)組定義中的那個(gè)分界下標(biāo)r)。但是,這個(gè)想法的一個(gè)最大問題是:給定一個(gè)循環(huán)遞增數(shù)組,我如何去確定其分界下標(biāo)r?最明顯的做法就是順序掃描一遍數(shù)組,然后確定其分界下標(biāo)r。但是,既然你都掃描一遍了,也就能確定檢索元素是否在該數(shù)組中了,何必再去利用分界下標(biāo)r去檢索呢?
????? 上述想法不成功,我們再去深入地去思考二分查找方法的一些原理特性。在一個(gè)嚴(yán)格遞增的數(shù)組中,我們將要檢索的元素和數(shù)組中間的元素進(jìn)行比較,然后根據(jù)要檢索的元素與數(shù)組中間的元素的大小關(guān)系來確定該元素落在那個(gè)范圍內(nèi),然后遞歸地在該范圍內(nèi)進(jìn)行檢索。
????? 現(xiàn)在在循環(huán)遞增數(shù)組中,我們不能簡單地通過與數(shù)組中間元素的大小關(guān)系來確定要檢索的元素所落在的區(qū)間范圍。要確定范圍,我們可以再加上要檢索的元素與數(shù)組兩端的元素的大小關(guān)系。
????? 循環(huán)遞增數(shù)組有這么一個(gè)性質(zhì):以數(shù)組中間元素將循環(huán)遞增數(shù)組劃分為兩部分,則一部分為一個(gè)嚴(yán)格遞增數(shù)組,而另一部分為一個(gè)更小的循環(huán)遞增數(shù)組。當(dāng)中間元素大于首元素時(shí),前半部分為嚴(yán)格遞增數(shù)組,后半部分為循環(huán)遞增數(shù)組;當(dāng)中間元素小于首元素時(shí),前半部分為循環(huán)遞增數(shù)組;后半部分為嚴(yán)格遞增數(shù)組。
記要檢索的元素為key,數(shù)組的首元素為a[low],中間元素為a[mid],末尾元素為a[high]。則當(dāng)key不等于a[mid] 時(shí),
??? 1、a[mid] > a[low],即數(shù)組前半部分為嚴(yán)格遞增數(shù)組,后半部分為循環(huán)遞增數(shù)組時(shí),若key小于a[mid]并且不小于a[low]時(shí),則key落在數(shù)組前半部分;否則,key落在數(shù)組后半部分。
??? 2、a[mid] < a[high],即數(shù)組前半部分為循環(huán)遞增數(shù)組,后半部分為嚴(yán)格遞增數(shù)組時(shí),若key大于a[mid]并且不大于a[high]時(shí),則key落在數(shù)組后半部分;否則,key落在數(shù)組前半部分。
通過上面利用數(shù)組首元素,中間元素和末尾元素確定要檢索的元素所在范圍,我們就可以使用修改后的二分查找算法了。
實(shí)現(xiàn)代碼如下:
// 改進(jìn)后的二分搜索 int Search(int A[],int n, int num) {int left = 0 ;int right = n - 1 ;int mid = 0 ;int pos = -1 ; //返回-1,表示查找失敗while(left <= right){mid = (left + right)/2 ;if (A[mid] == num){ pos = mid ; break; }if (A[left] <= A[mid]) //前半部分是嚴(yán)格遞增的,后半部分是一個(gè)更小的循環(huán)遞增數(shù)組{if(A[left] <= num && num < A[mid] ){right = mid - 1 ;}else{left = mid + 1 ;} }else //后半部分是嚴(yán)格遞增的,前半部分是一個(gè)更小的循環(huán)遞增數(shù)組{if ( A[mid] < num && num <= A[right]){left = mid + 1 ;}else{right = mid - 1 ;}}}return pos; }
二分搜索的模板如下:
// 二分搜索 int BinarySearch(int *num, int key, int low, int high) {int mid ;while(low <= high) //切記:條件是 <= ,很多次都不小心寫成了 < ,導(dǎo)致了N多WA{mid = (low + high)>>1;if(num[mid] == key)return mid;else if(num[mid] < key)low = mid + 1;elsehigh = mid -1;}return low; //查找不成功時(shí),返回應(yīng)該插入的位置,或者直接返回-1,表示查找失敗也是可以的 } ????? 二分搜索的擴(kuò)展:對已排好序的數(shù)組A,一般來說可用二分查找 可以很快找到。現(xiàn)有一特殊數(shù)組A[],它是循環(huán)遞增的,如A[]={ 17 19 20 25 1 4 7 9},試在這樣的數(shù)組中找一元素x,看看是否存在。請寫出你的算法,必要時(shí)可寫偽代碼,并分析其空間、時(shí)間復(fù)雜度。
????? 對于循環(huán)有序的數(shù)組,它是循環(huán)遞增的,例如:A[]={ 17 19 20 25 1 4 7 9},也可以使用二分搜索:每次將數(shù)組分為2部分,一個(gè)是單調(diào)遞增的,一個(gè)是循環(huán)遞增的。如果是單調(diào)遞增的話直接使用樸素的二分搜索,如果是循環(huán)遞增的話繼續(xù)使用特殊二分搜索下去。
思路分析:
????? 在一個(gè)數(shù)組中檢索一個(gè)元素,最普通的算法就是時(shí)間復(fù)雜度為O(n)的順序檢索。要降低時(shí)間復(fù)雜度,并結(jié)合循環(huán)遞增數(shù)組的元素已有一定程度順序的性質(zhì),很容易想到二分查找。
????? 我最初的想法是:樸素的二分查找在是下標(biāo)區(qū)間[0 n-1]內(nèi)進(jìn)行二分,那么利用循環(huán)遞增的性質(zhì),我們可以在數(shù)組的有效下標(biāo)區(qū)間[0 n-1]的一個(gè)偏移區(qū)間[r+1 n+r-1]里進(jìn)行二分(其中r是上述循環(huán)遞增數(shù)組定義中的那個(gè)分界下標(biāo)r)。但是,這個(gè)想法的一個(gè)最大問題是:給定一個(gè)循環(huán)遞增數(shù)組,我如何去確定其分界下標(biāo)r?最明顯的做法就是順序掃描一遍數(shù)組,然后確定其分界下標(biāo)r。但是,既然你都掃描一遍了,也就能確定檢索元素是否在該數(shù)組中了,何必再去利用分界下標(biāo)r去檢索呢?
????? 上述想法不成功,我們再去深入地去思考二分查找方法的一些原理特性。在一個(gè)嚴(yán)格遞增的數(shù)組中,我們將要檢索的元素和數(shù)組中間的元素進(jìn)行比較,然后根據(jù)要檢索的元素與數(shù)組中間的元素的大小關(guān)系來確定該元素落在那個(gè)范圍內(nèi),然后遞歸地在該范圍內(nèi)進(jìn)行檢索。
????? 現(xiàn)在在循環(huán)遞增數(shù)組中,我們不能簡單地通過與數(shù)組中間元素的大小關(guān)系來確定要檢索的元素所落在的區(qū)間范圍。要確定范圍,我們可以再加上要檢索的元素與數(shù)組兩端的元素的大小關(guān)系。
????? 循環(huán)遞增數(shù)組有這么一個(gè)性質(zhì):以數(shù)組中間元素將循環(huán)遞增數(shù)組劃分為兩部分,則一部分為一個(gè)嚴(yán)格遞增數(shù)組,而另一部分為一個(gè)更小的循環(huán)遞增數(shù)組。當(dāng)中間元素大于首元素時(shí),前半部分為嚴(yán)格遞增數(shù)組,后半部分為循環(huán)遞增數(shù)組;當(dāng)中間元素小于首元素時(shí),前半部分為循環(huán)遞增數(shù)組;后半部分為嚴(yán)格遞增數(shù)組。
記要檢索的元素為key,數(shù)組的首元素為a[low],中間元素為a[mid],末尾元素為a[high]。則當(dāng)key不等于a[mid] 時(shí),
??? 1、a[mid] > a[low],即數(shù)組前半部分為嚴(yán)格遞增數(shù)組,后半部分為循環(huán)遞增數(shù)組時(shí),若key小于a[mid]并且不小于a[low]時(shí),則key落在數(shù)組前半部分;否則,key落在數(shù)組后半部分。
??? 2、a[mid] < a[high],即數(shù)組前半部分為循環(huán)遞增數(shù)組,后半部分為嚴(yán)格遞增數(shù)組時(shí),若key大于a[mid]并且不大于a[high]時(shí),則key落在數(shù)組后半部分;否則,key落在數(shù)組前半部分。
通過上面利用數(shù)組首元素,中間元素和末尾元素確定要檢索的元素所在范圍,我們就可以使用修改后的二分查找算法了。
實(shí)現(xiàn)代碼如下:
// 改進(jìn)后的二分搜索 int Search(int A[],int n, int num) {int left = 0 ;int right = n - 1 ;int mid = 0 ;int pos = -1 ; //返回-1,表示查找失敗while(left <= right){mid = (left + right)/2 ;if (A[mid] == num){ pos = mid ; break; }if (A[left] <= A[mid]) //前半部分是嚴(yán)格遞增的,后半部分是一個(gè)更小的循環(huán)遞增數(shù)組{if(A[left] <= num && num < A[mid] ){right = mid - 1 ;}else{left = mid + 1 ;} }else //后半部分是嚴(yán)格遞增的,前半部分是一個(gè)更小的循環(huán)遞增數(shù)組{if ( A[mid] < num && num <= A[right]){left = mid + 1 ;}else{right = mid - 1 ;}}}return pos; }
總結(jié)
以上是生活随笔為你收集整理的二分搜索及其扩展(循环递增数组的搜索)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2012 人民搜索 实习生招聘 笔试题
- 下一篇: 经典面试题:链表的相交与环问题