前段時間,在論壇上看到有統計說有90%的程序員不可以寫對簡單的二分法。二分法不是很簡單的嗎? 這難道不是聳人聽聞?程序員
其實,二分法真的不那麼簡單,尤爲是二分法的各個變種。 最最簡單的二分法,就是從一個排好序的數組之查找一個key值。 以下面的程序。算法
/**
* 二分查找,找到該值在數組中的下標,不然爲-1
*/
static int binarySerach(int[] array, int key) {
int left = 0;
int right = array.length - 1;
// 這裏必須是 <=
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] == key) {
return mid;
}
else if (array[mid] < key) {
left = mid + 1;
}
else {
right = mid - 1;
}
}
return -1;
}
複製代碼
這個程序,相信只要是一個合格的程序員應該都會寫。 稍微注意一點, 每次移動left和right指針的時候,須要在mid的基礎上+1或者-1, 防止出現死循環, 程序也就可以正確的運行。數組
但若是條件稍微變化一下, 你還會寫嗎?如,數組之中的數據可能能夠重複,要求返回匹配的數據的最小(或最大)的下標;更近一步, 須要找出數組中第一個大於key的元素(也就是最小的大於key的元素的)下標,等等。 這些,雖然只有一點點的變化,實現的時候確實要更加的細心。 下面列出了這些二分檢索變種的實現。bash
// 查找第一個相等的元素
static int findFirstEqual(int[] array, int key) {
int left = 0;
int right = array.length - 1;
// 這裏必須是 <=
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] >= key) {
right = mid - 1;
}
else {
left = mid + 1;
}
}
if (left < array.length && array[left] == key) {
return left;
}
return -1;
}
複製代碼
// 查找最後一個相等的元素
static int findLastEqual(int[] array, int key) {
int left = 0;
int right = array.length - 1;
// 這裏必須是 <=
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] <= key) {
left = mid + 1;
}
else {
right = mid - 1;
}
}
if (right >= 0 && array[right] == key) {
return right;
}
return -1;
}
複製代碼
// 查找第一個等於或者大於key的元素
static int findFirstEqualLarger(int[] array, int key) {
int left = 0;
int right = array.length - 1;
// 這裏必須是 <=
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] >= key) {
right = mid - 1;
}
else {
left = mid + 1;
}
}
return left;
}
複製代碼
// 查找第一個大於key的元素
static int findFirstLarger(int[] array, int key) {
int left = 0;
int right = array.length - 1;
// 這裏必須是 <=
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] > key) {
right = mid - 1;
}
else {
left = mid + 1;
}
}
return left;
}
複製代碼
// 查找最後一個等於或者小於key的元素
static int findLastEqualSmaller(int[] array, int key) {
int left = 0;
int right = array.length - 1;
// 這裏必須是 <=
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] > key) {
right = mid - 1;
}
else {
left = mid + 1;
}
}
return right;
}
複製代碼
// 查找最後一個小於key的元素
static int findLastSmaller(int[] array, int key) {
int left = 0;
int right = array.length - 1;
// 這裏必須是 <=
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] >= key) {
right = mid - 1;
}
else {
left = mid + 1;
}
}
return right;
}
複製代碼
接下來,你們能夠對這四種變種算法進行相應的測試。測試
不少的時候,應用二分檢索的地方都不是直接的查找和key相等的元素,而是使用上面提到的二分檢索的各個變種,熟練掌握了這些變種,當你再次使用二分檢索的檢索的時候就會感受的更加的駕輕就熟了。ui