一、什么是二分查找
二分查找也稱折半查找(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; 解決此問題。
五、二分查找的優缺點:
優點:比較次數少,查找速度快,平均性能好。
缺點:必須有序,必須是數組。