二分法查詢演算法
阿新 • • 發佈:2018-11-09
二分法查詢具有驚人的查詢速度,尤其是對於海量資料的時候,作用更加明顯,時間複雜度用大O表示法,即是(logn),這種(logn)時間複雜度是非常神奇的,比如 n 等於 2 的 32 次方,這個數很大了吧?大約是42億,也就是說,如果我們在 42 億個資料中用二分查詢一個數據,最多需要比較 32 次。
但是,二分查詢是有侷限性的:
(1)二分查詢依賴的是順序表結構,簡單點說就是陣列。
解釋:主要原因是二分查詢演算法需要按照下標隨機訪問元素。
(2)二分查詢針對的是有序資料。
(3)資料量太小不適合二分查詢。
(4)資料量太大也不適合二分查詢。
解釋:二分查詢的底層需要依賴陣列這種資料結構,而陣列為了支援隨機訪問的特性,要求記憶體空間連續,對記憶體的空間要求比較苛刻。比如,我們有1GB的資料,那就需要1GB記憶體空間。
接下來是二分演算法的程式碼了:
1 //二分法查詢給定值 普通Java實現 2 public int bsearch(int[] a, int n, int value) { 3 int low = 0; 4 int high = n - 1; 5 6 while (low <= high) { 7 int mid = (low + high) / 2; 8 if (a[mid] == value) { 9 return mid; 10 } else if (a[mid] < value) {11 low = mid + 1; 12 } else { 13 high = mid - 1; 14 } 15 } 16 17 return -1; 18 } 19 20 // 二分查詢的遞迴實現 21 public int bsearch(int[] a, int n, int val) { 22 return bsearchInternally(a, 0, n - 1, val); 23 } 24 25 private int bsearchInternally(int[] a, int low, int high, intvalue) { 26 if (low > high) return -1; 27 28 int mid = low + ((high - low) >> 1); 29 if (a[mid] == value) { 30 return mid; 31 } else if (a[mid] < value) { 32 return bsearchInternally(a, mid+1, high, value); 33 } else { 34 return bsearchInternally(a, low, mid-1, value); 35 } 36 } 37 38 //查詢第一個值等於給定值的元素 39 public int bsearch1(int[] a, int n, int value){ 40 int low = 0; 41 int high = n - 1; 42 43 while(low <= high){ 44 //這裡用到的(右移)>>運算子 右移運算子簡單理解就是 除以2的移動次冪 下面這個就是 等同於(high-low)/2^1 45 int mid = low + ((high-low) >> 1); 46 if(a[mid] > value){ 47 //說明value 在前半部分 把排好序的陣列 從中間一切兩半 48 high = mid - 1; 49 }else if(a[mid] < value){ 50 //說明value 在後半部分 51 low = mid + 1; 52 }else{ 53 //a[mid] == value 54 //但是我們要查詢的是第一個 等於改定值的元素 還需要確認一下a[mid] 是不是第一個 55 if(mid == 0 || a[mid - 1] != value){ 56 //當mid == 0 的時候,說明這是第一個元素,肯定是我們要找的 57 //當a[mid] 前面的元素不等於 value的時候,說明a[mid]肯定就是第一個等於給定值的元素 58 //因為該陣列是有序的,這裡就是預設從小到大排序 59 return mid; 60 }else{ 61 high = mid - 1; 62 } 63 } 64 } 65 //這個 -1 代表的就是沒有找到 66 return -1; 67 } 68 69 //查詢最後一個值等於給定元素 70 public int bsearch2(int[] a, int n, int value){ 71 int low = 0; 72 int high = n - 1; 73 74 while(low <= high){ 75 int mid = low + ((low+high) >> 1); 76 if(a[mid] > value){ 77 high = mid - 1; 78 }else if(a[mid] < value){ 79 low = mid + 1; 80 }else{ 81 if(mid == n-1 || a[mid+1] != value){ 82 //同理 83 return mid; 84 }else{ 85 low = mid + 1; 86 } 87 } 88 } 89 return -1; 90 } 91 92 //查詢第一個大於等於給定值的元素 93 public int bsearch3(int[] a, int n, int value){ 94 int low = 0; 95 int high = n - 1; 96 97 while(low <= high){ 98 int mid = low + ((low+high) >> 1); 99 if(a[mid] >= value){ 100 if(mid == 0 || a[mid-1] < value){ 101 //a[mid] 是第一個數,但是a[mid]大於等於value的數,所以肯定就是它了 102 //a[mid - 1] 是小於 value 的數,它的前一個數是小於value的,肯定也是它了 103 return mid; 104 }else{ 105 high = mid - 1; 106 } 107 }else{ 108 low = mid + 1; 109 } 110 } 111 return -1; 112 } 113 114 //查詢最後一個小於等於給定值得元素 115 public int bsearch4(int[] a, int n, int value){ 116 int low = 0; 117 int high = n -1; 118 119 while(low <= high){ 120 int mid = low + ((low+high) >> 1); 121 if(a[mid] > value){ 122 high = mid - 1; 123 }else{ 124 if(mid == n-1 || a[mid+1] > value){ 125 //同理 126 return mid; 127 }else{ 128 low = mid + 1; 129 } 130 } 131 } 132 return -1; 133 }