插值查找:
二分查找在確定中間值的位置的時候,使用的公式爲:
mid = (right + left) / 2
此公式可以轉換爲:mid = left + (right - left) / 2
上面的公式中 1/2 我們可以進行優化:
設要查找的值爲 targetVal
(targetVal - a[left]) / (a[right] - a[left]) * (right - left)
此公shi能夠比較快速的定位到 targetVal傾向於偏到哪一個方向
因此有 mid = left + (right - left) * (targetVal - a[left]) / (a[right] - a[left])
優於 mid = left + (right - left) / 2,同樣插值查找也需要數組是有序的,在a中的值分佈不均勻,跳躍性很大的
情況下,插值查找不一定比二分查找好
代碼:
public class InsertValueSearch {
public static void main(String[] args) {
int len = 100;
int[] a = new int[len];
for ( int i = 0; i < len; i++) {
a[i] = i;
}
int findVal = 45;
int pos = insertSearch(a, 0, a.length-1, findVal);
System.out.printf("要查找的值爲:%d, pos:%d\n", findVal, pos);
}
//找到返回對應的下標,找不到返回-1
public static int insertSearch(int a[], int left, int right, int findVal) {
System.out.println("Hello~~");
//插值查找 findVal < a[left] || a[right] < findVal 必須有
if (left > right || findVal < a[left] || a[right] < findVal) {
return -1;
}
int mid = left + (right - left) * (findVal - a[left]) / (a[right] - a[left]);
int midVal = a[mid];
if (findVal > midVal) {
return insertSearch(a, mid+1, right, findVal);
} else if (findVal < midVal) {
return insertSearch(a, left, mid-1, findVal);
} else {
return mid;
}
}
}
斐波那契查找
0.618讓人看了很舒服 在二分查找確定 1/2的時候,我們可以確定0.618 斐波那契數前一個數比上後一個數的比例接近於0.618
代碼:
public class FibonacciSearch {
public static void main(String[] args) {
int len = 100;
int[] a = new int[len];
for ( int i = 0; i < len; i++) {
a[i] = i;
}
int[] a1 = {1, 8, 10,89,1000,1234};
int findVal = 45;
int i = fibonacciSearch(a1, findVal);
}
public static int fibonacciSearch(int a[], int findVal) {
int low = 0;
int high = a.length - 1;
int k = 0;
int mid = 0; //
int f[] = fib(20);
//獲取到斐波那契數值的下標
while (high > f[k] - 1) {
k++;
}
//因爲f[k] 值可能大於數組的長度,因此使用Arrays類構造一個新的數組,並指向a[]
//不足的部分使用0填充
int[] tmp = Arrays.copyOf(a, f[k]);
//需要使用a數組最後的數填充tmp
for (int i = high+1; i < tmp.length; i++) {
tmp[i] = a[high];
}
//循環查找,直到找到目標數
while (low <= high) {
mid = low + f[k-1] -1;
if (findVal < tmp[mid]) { //向數組前面查找
high = mid-1;
k--; //全部元素 = 前面的元素 + 後面的元素。 f[k] = f[k-1] + f[k-2]
//前面有f[k-1]個元素,所以可以繼續拆分 f[k-1] = f[k-2] + f[k-3],即在f[k-1]的前面繼續查找
} else if (findVal > tmp[mid]) { //想數組後面查找
low = mid+1;
k -= 2; //全部元素 = 前面元素 + 後面元素
//f[k] = f[k-1]+ f[k-2], 因爲f
} else {
//需要確定返回的是哪一個座標
if (mid <= high) {
return mid;
} else {
return high;
}
}
}
return -1;
}
//非遞歸方法獲取斐波那契數列
public static int[] fib(int maxSize) {
int[] f = new int[maxSize];
if (maxSize < 2) {
f = new int[2];
}
f[0]= 1;
f[1] = 1;
for (int i = 2; i < f.length; i++) {
f[i] = f[i-1]+f[i-2];
}
return f;
}
}