日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

搜索技术【二分搜索】 - 简介 原理

發布時間:2024/3/24 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 搜索技术【二分搜索】 - 简介 原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

搜索技術【二分搜索】 - 簡介 & 原理

【舉個栗子】

某大型娛樂節目在玩猜數游戲,主持人在女嘉賓的手心寫一個10以內的整數,讓女嘉賓的老公猜數字是多少,而女嘉賓只能提示老公猜的數字是大了還是小了,并且只有3次機會。

主持人悄悄地在女嘉賓手心寫了一個8。

女嘉賓的老公: “2。” 女嘉賓: “小了?!?女嘉賓的老公: “3?!?女嘉賓: “小了。” 女嘉賓的老公: “10?!?女嘉賓: “還是沒猜對?!?

那么,你有沒有辦法以最快的速度猜出來呢?

從問題描述來看,如果有n 個數,那么在最壞情況下需要猜n 次才能成功,其實完全沒有必要一個一個地猜,因為這些數是有序的,可以使用二分搜索策略,每次都和中間的元素做比較,如果比中間的元素小,則在前半部分查找;如果比中間的元素大,則在后半部分查找。

這種方法被稱為二分查找折半查找,也被稱為二分搜索技術。

【原理】 - 二分搜索技術

例如,給定有n 個元素的序列,這些元素是有序的(假定為升序),從序列中查找元素x 。

用一維數組S []存儲該有序序列,設變量low和high表示查找范圍的下界和上界,middle表示查找范圍的中間位置,x 表示特定的查找元素。

[算法步驟]

① 初始化。令low=0,即指向有序數組S []的第1個元素;high=n ?1,即指向有序數組S []的最后一個元素。

② 判定low≤high是否成立,如果成立,則轉向步驟3,否則算法結束。

③ middle=(low+high)/2,即指向查找范圍的中間元素。如果數量較大,則為避免low+high溢出,可以采用middle=low+(high - low)/2。

④ 判斷x 與S [middle]的關系。如果x =S [middle],則搜索成功,算法結束;如果x >S [middle],則令low=middle+1;否則令high=middle?1,轉向步驟2。

[舉個栗子]

例如,在有序序列(5,8,15,17,25,30,34,39,45,52,60)中查找元素17。

① 數據結構。用一維數組S []存儲該有序序列,x =17。

② 初始化。low=0,high=10,計算middle=(low+high)/2=5。

③ 將x 與S [middle]做比較。x =17,S [middle]=30,在序列的前半部分查找,令high=middle?1,搜索的范圍縮小到子問題S [0…middle?1]。

④ 計算middle=(low+high)/2=2。

⑤ 將x 與S [middle]做比較。x =17,S [middle]=15,在序列的后半部分查找,令low=middle+1,搜索的范圍縮小到子問題S[middle+1…high]。

⑥ 計算middle=(low+high)/2=3。

⑦ 將x 與S [middle]做比較。x =S [middle]=17,查找成功,算法結束。

[算法實現]

用BinarySearch(int n , int s [], int x )函數實現二分查找算法,其中n 為元素個數,s []為有序數組,x 為待查找的元素。low指向數組的第1個元素,high指向數組的最后一個元素。如果low≤high,middle=(low+high)/2,即指向查找范圍的中間元素。如果x =S[middle],則搜索成功,算法結束;如果x >S [middle],則令low=middle+1,在后半部分搜索;否則令high=middle?1,在前半部分搜索。

① 非遞歸算法。

int BinarySearch(int s[] , int n , int s){ //二分查找非遞歸算法int low = 0, high = n - 1; //low指向數組的第1個元素,high指向數組的最后一個元素while(low <= high){int middle = (low + high) / 2; //middle為查找范圍的中間值if(x == s[middle]){ //x 等于查找范圍的中間值,算法結束return middle;}else if(x > s[middle]){ //x 大于查找范圍的中間元素,在后半部分查找low = middle + 1; }else{ //x小于查找范圍的中間元素,在前半部分查找high = middle - 1;}}return -1; }

② 遞歸算法。遞歸有自調用問題,增加兩個參數low和high標記搜索范圍的開始和結束。

int recursionBS(int s[] . int x , int low ,int high){ //二分查找遞歸算法//low 指向搜索區間的第1個元素,high 指向搜索區間的最后一個元素if(low > high){ ///遞歸結束條件return -1;}int middle = (low + high) / 2; //計算middle值(查找范圍的中間值)if(x == s[middle]){ //x 等于s[middle],查找成功,算法結束return middle;}else if(x < s[middle]){ //x 小于s[middle],在前半部分查找return recursionBS(s , x ,low , middle - 1);}else{ //x 大于s[middle],在后半部分查找return recursionBS(s , x ,middle + 1 , high);} }

[算法分析]

① 時間復雜度

怎么計算二分查找算法的時間復雜度呢?如果用T (n )來表示n 個有序元素的二分查找算法的時間復雜度,那么結果如下。

  • 當n =1時,需要一次做比較,T (n )=O (1)。
  • 當n >1時,將待查找元素和中間位置元素做比較,需要O (1)時間,如果比較不成功,那么需要在前半部分或后半部分搜索,問題的規??s小了一半,時間復雜度變為T (n /2)。

  • 當n >1時,可以遞推求解如下:

遞推最終的規模為1,令n =2^x ,則x =log n 。

二分查找的非遞歸算法和遞歸算法查找的方法是一樣的,時間復雜度相同,均為O (logn )。

② 空間復雜度

在二分查找的非遞歸算法中,變量占用了一些輔助空間,這些輔助空間都是常數階的,因此空間復雜度為O (1)。

二分查找的遞歸算法,除了使用一些變量,還需要使用棧來實現遞歸調用。在遞歸算法中,每一次遞歸調用都需要一個??臻g存儲,我們只需看看有多少次調用即可。假設原問題的規模為n ,首先第1次遞歸就分為兩個規模為n /2的子問題,這兩個子問題并不是每個都執行,只會執行其中之一,因為與中間值做比較后,要么在前半部分查找,要么在后半部分查找;然后把規模為n /2的子問題繼續劃分為兩個規模為n/4的子問題,選擇其一;繼續分治下去,在最壞情況會分治到只剩下一個數值,那么算法執行的節點數就是從樹根到葉子所經過的節點,每一層執行一個,直到最后一層,如下圖所示。

遞歸調用最終的規模為1,即n /2 ^x =1,則x =logn 。假設陰影部分是搜索經過的路徑,一共經過了logn 個節點,也就是說遞歸調用了logn 次。遞歸算法使用的棧空間為遞歸樹的深度,因此二分查找遞歸算法的空間復雜度為O (logn )。在二分搜索中需要注意以下幾個問題。

① 必須滿足有序性。

② 搜索范圍。初始時,需要指定搜索范圍,如果不知道具體范圍,則對正數可以采用范圍[0,inf],對負數可以采用范圍[-inf,inf],inf為無窮大,通常設定為0x3f3f3f3f。

③ 二分搜索。在一般情況下,mid=(l +r )/2或mid=(l +r)>>1。如果l 和r 特別大,則為了避免l +r 溢出,可以采用mid=l +(r-l )/2。對判斷二分搜索結束的條件,以及判斷mid可行時是在前半部分搜索,還是在后半部分搜索,需要具體問題具體分析。

④ 答案是什么。在減少搜索范圍時,要特別注意是否漏掉了mid點上的答案。

====================================================

二分搜索分為整數上的二分搜索和實數上的二分搜索,大致過程如下。

① 整數上的二分搜索

整數上的二分搜索,因為縮小搜索范圍時,有可能r =mid-1或l=mid+1,因此可以用ans記錄可行解。對是否需要減1或加1,要根據具體問題來分析。

l = a ; r = b; //初始搜索范圍 while(l <= r){int mid = (l + r) / 2;if(judge(mid)){ans = mid; //記錄可行解r = mid - 1;}else{l = mid + 1;} } return ans;

② 實數上的二分搜索

實數上的二分搜索不可以直接比較大小,可以將r -l >eps作為循環條件,eps為一個較小的數,例如1e-7等。為避免丟失可能解,縮小范圍時r =mid或l =mid,在循環結束時返回最后一個可行解。

l = a; r = b; //初始搜索范圍 while(r - l>eps){ //判斷差值double mid = (l + r) / 2;if(judge(mid)){l = mid; //l 記錄了可行解,在循環結束時返回答案l}else{r = mid;} } return l;

還可以運行固定的次數,例如運行100次,可達10^-30 精度,在一般情況下都可以解決問題

l = a ; r = b; for(int i = 0 ; i < 100 ; i++){ //運行100次double mid = (l + r) / 2;if(judge(mid)){l = mid;}else{r = mid;} } return l;

總結

以上是生活随笔為你收集整理的搜索技术【二分搜索】 - 简介 原理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。