二分查找(折半查找)


一、什么是二分查找

二分查找也稱折半查找(Binary Search),它是一種效率較高的查找方法。但是,折半查找要求線性表必須采用順序存儲結構,而且表中元素按關鍵字有序排列

 

二、算法復雜度

 

二分查找的基本思想是將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)

三、如何理解二分查找

給定范圍0到1000的整數:

第一次我們選擇500,發現偏大了,

那么下一次的選擇范圍,就變成了1到499:

第二次我們選擇250,發現還是偏大了,

那么下一次的選擇范圍,就變成了1到249:

第三次我們選擇125,發現偏小了,

那么下一次的選擇范圍,就變成了126到249:

以此類推,最壞的情況需要猜測多少次呢?

答案是 log1000 = 10次,

也就是讓原本的區間范圍進行10次 “折半”。

四、代碼實現

1.非遞歸方式

 1 import java.util.Arrays;
 2 
 3 public class test07 {
 4     public static void main(String[] args) {
 5         int[] arr = new int[]{15,66,48,9,54,11,87,100,40,8,9,7,12,13};
 6         int key = 11;  //要查找的數
 7         Arrays.sort(arr);  //二分查找,之前一定要對數組進行元素排序
 8         System.out.println(Arrays.toString(arr));   //打印數組
 9         System.out.println(key+"元素的索引"+binarySearch(arr,key));
10     }
11     public static int binarySearch(int[] array,int key){
12         //頭指針初始位置
13         int low = 0;
14         //尾指針初始位置
15         int high = array.length - 1;
16         //判斷查找的數是否在數組中,如果此處不加判斷,則可能報java.lang.StackOverflowError棧內存溢出
17         if(low>high||key>array[high]||key<array[low]){
18             return -1;
19         }
20         while(low<=high){
21             //計算中間值的索引,防止溢出
22             int mid = low+ (high - low)/2;
23             if(key==array[mid]){
24                 return mid;    //返回查詢到的索引位置
25             }else if (key>array[mid]){
26                 low = mid+1; //mid所對應的的值比key小,key應該在右邊
27             }else {
28                 high = mid-1;  //mid所對應的的值比key大,key應該在左邊
29             }
30         }
31         //若沒有,則返回-1
32         return -1;
33     }
34 }

2.非遞歸方式

 1 import java.lang.annotation.ElementType;
 2 import java.util.Arrays;
 3 
 4 public class test07 {
 5     public static void main(String[] args) {
 6         int[] arr = new int[]{15,66,48,9,54,11,87,100,40,8,9,7,12,13};
 7         int key = 11;  //要查找的數
 8         //頭指針初始位置
 9         int low = 0;
10         //尾指針初始位置
11         int high = arr.length - 1;
12         Arrays.sort(arr);  //二分查找,之前一定要對數組進行元素排序
13         System.out.println(Arrays.toString(arr));   //打印數組
14         System.out.println(key+"元素的索引"+binarySearch(arr,low,high,key));
15     }
16     public static int binarySearch(int[] array,int low,int high,int key){
17         //判斷查找的數是否在數組中,如果此處不加判斷,則可能報java.lang.StackOverflowError棧內存溢出
18         if(low>high||key>array[high]||key<array[low]){
19             return -1;
20         }
21         //計算中間值的索引,防止溢出
22         int mid = low+ (high - low)/2;
23         if (key>array[mid]){
24             return binarySearch(array,mid+1,high,key);     //mid所對應的的值比key小,key應該在右邊
25         }else if(key<array[mid]){
26             return binarySearch(array,low,mid-1,key); //mid所對應的的值比key大,key應該在左邊
27         }else{
28             return mid;
29         }
30     }
31 }

二分查找中值(mid)計算 二分查找中值計算有三種方式:

  • int mid = (low + high)/ 2;
  • int mid = low + (high - low) / 2;
  • int mid = (high + low) >>> 1
  • 上述兩種算法看似第一種要簡潔,第二種提取之后,跟第一種沒有什么區別。但是實際上上述兩種計算是有區別的,
  • 第一種的做法是在極端情況下計算的,(low + high)存在着溢出的風險,進而有可能得到錯誤的mid結果,導致程序錯誤;
  • 而第二種算法能夠保證計算出來的mid值一定大於low、小於high,不存在溢出的問題。
  • 針對第一種算法為了防止溢出問題,可以使用:int mid = (high + low) >>> 1; 解決此問題。

五、二分查找的優缺點:

優點:比較次數少,查找速度快,平均性能好。

缺點:必須有序,必須是數組。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM