很容易理解,可是二分查找的前提是序列是有序的。每次都是經過跟區間的中間元素對比,將待查找的區間縮小爲以前的一半,直到找到要查找的元素,或者區間被縮小爲0。
二分查找只能用在數據是經過順序表結構存儲的數據結構上,如數組,若是是其餘的結構存儲則不適合用二分查找,如鏈表。
二分查找的時間複雜度爲O(logn).
簡答二分查找的代碼以下:算法
int binarySearch(int A[], int n, int x){ //left 和right爲數組的左右區間下標 int left = 0, right =n-1, mid; while(left <= right){ mid = left + ( right - left) / 2; //當數組數量較多時爲了防止left+right超過int範圍。 if(A[mid] == x) return mid; //找到x,返回下標 else if(A[mid] > x){ right = mid-1; } else{ left = mid+1; } } return -1; //沒有找到,返回-1。 }
若是序列A中的元素可能重複,因此查找時會出現如下變體類型的二分查找。該思想是在學習極客時間的王錚數據結構與算法時學習的,對我來講比不少書上寫得更加容易理解和記憶。數組
由於數組中有重複值,找到的x不必定是第一個出現的,因此能夠在上面簡單二分查找的基礎上判斷當A[mid]=x 時,判斷是否是第一個,若是此時mid=0或者A[mid-1]!=x,則說明x確定爲第一個出現;若A[mid-1]=x,則要更新right = mid-1,由於此時第一個x確定在[left, mid-1]之間。代碼以下:數據結構
//查找第一個等於x的位置 int findfirstX(int A[], int n, int x){ int left = 0, right = n-1; int mid; while(left <= right){ mid = left + ((right-left) >> 1); if(A[mid] > x){ right = mid-1; }else if(A[mid] < x){ left = mid + 1; }else{ if(mid == 0 || A[mid-1] != x) return mid; else right = mid-1; } } return -1; }
該問題和上面一樣的思路,要判斷mid是否爲n-1,或者A[mid+1]即後一個是否爲x,而後進行更新返回。學習
//查找最後一個等於x的元素位置 int findlastX(int A[], int n, int x){ int left = 0, right = n-1, mid; while(left <= right){ mid = left + ((right-left) >> 1); if(A[mid] > x){ right = mid-1; }else if(A[mid] < x){ left = mid + 1; }else{ if(mid == n-1 || A[mid+1] != x) return mid; else left = mid+1; } } return -1; }
思路和前面兩種相似,若是A[mid]小於要查找的值value,那要查找的值確定在[mid+1, high]之間,若是A[mid] 大於等於給定的值x,要先看下這個mid=0 || A[mid-1] < x,則此時確定時第一個大於等於x的值。不然A[mid-1]>x,則要找的值確定在[left, mid-1]之間,因此更新right = mid-1;code
//查找第一個大於等於x的元素位置 int Upperfind(int A[], int n, int x){ int left = 0, right = n-1, mid; while(left <= right){ mid = left + ((right-left) >> 1); if(A[mid] >= x){ if((mid==0) || (A[mid-1] < x)) return mid; else right = mid-1; }else{ left = mid+1; } } }
思路同上面同樣。代碼以下:get
//查找最後一個小於等於x的元素位置 int boundfind(int A[], int n, int x){ int left =0, right = n-1, mid; while(left <= right){ mid = left + ((right- left) >> 1); if(A[mid] <= x){ if((mid==n-1) || (A[mid+1] > x)) return mid; else left = mid+1; }else{ right = mid-1; } } }
//查找第一個大於x的元素位置 int findlargeX(int A[], int n, int x){ int left =0 ,right = n-1, mid; while(left <= right){ mid = left + ((right- left) >> 1); if(A[mid] > x){ if((mid==0) || (A[mid-1] < x)) return mid; else right = mid - 1; }else{ left = mid + 1; } } return -1; }
參考資料:
極客時間 王崢算法課程:https://time.geekbang.org/column/article/42520
算法筆記 胡凡 曾磊ast