二分查找算法,是在大學階段學習的基礎性算法。算法思想簡單,但要寫出一個正確的二分查找算法並不簡單,從1946年提出,到1962年才完成一個正確的二分查找排序算法。二分查找排序算法的變種,也經常出如今各個IT公司的面試題中。本文總結資料嘗試給出一個「正確」的二分查找算法,最後給出一個二分查找排序的變種問題。面試
1. 經典二分查找排序的算法:算法
1 int BinarySearch(int* array, int n, int x) 2 { 3 assert((array != NULL) && (0 <= n)); 4 5 int low = 0; 6 int high = n -1; 7 8 while (low <= high) 9 { 10 int mid = low + ((high - low) >> 1); 11 if (array[mid] == x) 12 { 13 return mid; 14 } 15 if (x > array[mid]) 16 { 17 low = mid + 1; 18 } 19 else 20 { 21 high = mid -1; 22 } 23 } 24 return -1; 25 }
可能須要關注細節問題:數組
1)循環條件學習
在第8行,循環的條件設置成 low <=high。若是設置成low<high,是存在問題的:當只有數組只有一個元素,而且該元素就是須要查找的元素時,算法返回錯誤的值-1,查找失敗。spa
2)求中間元素code
在第10行,求中間元素使用的代碼:mid = low + ((high - low) >> 1)。一些書籍中給出的是:mid = (high + low) >> 1,若是high+low很大時,會形成溢出。這種狀況出現的機率較小,可是爲了程序適應比較惡劣條件,使用第10行代碼求中間元素就顯得有必要了。blog
(ps:上面的代碼可能還存在帶完善的地方,歡迎拍磚。。。)排序
2. 二分查找排序算法的變種it
問題描述:已知一個有序的數組a[N],循環左移k位(k<N)後獲得新的數組b[N],在這個新的數組中查找元素x。例如:數組 a[N] = {1, 3, 5, 7, 9, 10},循環左移2位後變成數組b[N]= {5, 7, 9, 10, 1, 3},在這個新的數組上查找某個元素x。class
上題是我在面試中問道的問題,比較慶幸的是我在《劍指offer》一書中碰到了相似的一題,書中須要找出數組b[N]最小的最小元素,所以能比較迅速的解決了這個問題。解決問題的思路和《劍指offer》提供的思路一致。
解題思路:數組b[N]中存在着兩個部分有序的子數組,b1:{5, 7, 9, 10}和b2:{1, 3},其中b1中的元素均大於b2中的元素。在使用二分查找算法時,中間元素mid一定落入b1或者b2某個遞增序列中,具體解決步驟以下:
Init: low = 0, high = N-1, mid = b[low + (high - low) >> 1]
step1: 求出數組b的中間元素mid, 若是mid == x,則返回成功,不然進入步驟step2。
step2: if(a[low]<mid),mid落入b1數組,此時:
1) if (a[low]<x<mid), x在有序區間[low, mid),則將high = mid -1
2) 不然,x落入區間(mid, high],則將low = mid +1
else mid落入b2數組,此時:
1)if (mid< x< b[high]),x在有序區間(mid, high],則將low = mid + 1
2)不然, x落入區間[low, mid),則將hign = mid -1
step3: if(low <= hign) 繼續步驟step1,不然返回查找失敗
具體的代碼以下:
1 int rotate_array_search(int a[], int n, int x) 2 { 3 int low = 0; 4 int high = n-1; 5 while(low <= high) 6 { 7 int mid = low + ((high - low) >> 1);
8 if(a[mid] == x) 9 return mid;
10 if(a[mid] >= a[low]) 11 { 12 if(x < a[mid] && x >= a[low]) 13 { 14 high = mid -1; 15 } 16 else 17 { 18 low = mid + 1; 19 } 20 } 21 else 22 { 23 if(x > a[mid] && x <= a[high]) 24 { 25 low = mid + 1; 26 }
else 27 { 28 high = mid -1; 29 } 30 } 31 } 32 return -1; // 查找失敗,則返回-1 33 }