問題:
如果一個數列已排序(從小到大),尋找指定元素在其中的位置。
解法:
利用數列已排序的特性,從數列的中間開始搜尋,如果這個數小於所搜尋的數,則該數左邊的數
一定都小於要搜尋的對象,所以無需浪費時間在左邊的數;如果搜尋的數大於所搜尋的對象,則右邊的
數無需再搜尋,直接搜尋左邊的數。如此類推,直到找到該元素,如果找不到則返回-1。
例如從數列-4, -2, 4, 6, 9, 14, 23, 100中找14。
1、首先從中間(0 + 7)/2=4開始:
< -4 -2 4 6 9 14 23 100 >
2、由於9小於23,所以搜尋右邊的數列
-4 -2 4 6 9 < 14 23 100 >
3、由於23大於14,所以搜尋左邊的數列
-4 -2 4 6 9 < 14 > 23 100
4、找到目標,返回位置5。
核心代碼:
1、 迭代實現
//迭代實現
static int search(int[] numbers, int num) {
int low = 0, high = numbers.length - 1;
int mid;
while (low < high) {
mid = (low + high) / 2;
if (numbers[mid] == num) //找到則返回
return mid;
if (numbers[mid] > num) //大於目標,找左邊
high = mid - 1;
else //小於目標,找右邊
low = mid + 1;
}
return -1; //找不到,返回-1
}
2、 遞迴實現
static int search(int[] numbers, int num, int low, int high) {
//下邊界大於上邊界,沒必要進行下去了
if(low > high)
return -1;
//中間值
int mid = (low + high) / 2;
if (numbers[mid] == num) //找到則返回
return mid;
if (numbers[mid] > num) //大於目標,找左邊
return search(numbers, num, low, mid - 1);
else //小於目標,找右邊
return search(numbers, num, mid + 1, high);
}
全部代碼:
Code
package com.icescut.classic.algorithm;
public class BinarySearch {
public static void main(String[] args) {
int[] numbers = { -4, -2, 4, 6, 9, 14, 23, 100 }; // 已排序
//遞迴實現
int res = search(numbers, 14,0,numbers.length);
System.out.println("position in " + res);
//迭代實現
res = search(numbers, 14);
System.out.println("position in " + res);
}
//遞迴實現
static int search(int[] numbers, int num, int low, int high) {
//下邊界大於上邊界,沒必要進行下去了
if(low > high)
return -1;
//中間值
int mid = (low + high) / 2;
if (numbers[mid] == num) //找到則返回
return mid;
if (numbers[mid] > num) //大於目標,找左邊
return search(numbers, num, low, mid - 1);
else //小於目標,找右邊
return search(numbers, num, mid + 1, high);
}
//迭代實現
static int search(int[] numbers, int num) {
int low = 0, high = numbers.length - 1;
int mid;
while (low < high) {
mid = (low + high) / 2;
if (numbers[mid] == num) //找到則返回
return mid;
if (numbers[mid] > num) //大於目標,找左邊
high = mid - 1;
else //小於目標,找右邊
low = mid + 1;
}
return -1; //找不到,返回-1
}
}
說明:
迭代實現與遞迴實現的思想都是一樣的,所是最好使用迭代以減少開銷。