斐波那契数列我们都知道{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 },前后的比值会越来越接近0.618,也就是黄金分割点。0.618也被公认为最具有审美意义的比例数字。斐波那契查找原理其实和二分法查找原理差不多,只不过计算中间值mid的方式不同,还有一点就是斐波那契查找的数组长度必须是f(k)-1,这样我们就可以把斐波那契数列进行划分 f(k)-1=f(k-1)+f(k-2)-1=[f(k-1)-1]+1+[f(k-2)-1];然后前面部分和后面部分都还可以继续进行划分。但实际上我们要查找的数组长度不可能都是f(k)-1,所以我们要补齐最后的部分,让数组的长度等于f(k)-1,让数组的最后一位数字把后面铺满。比如我们查找的数组长度是21,而f(8)-1=21-1=20;小于21,所以f(8)-1是不行的,我们需要把数组长度变为f(9)-1=34-1=33,后面多余的我们都用原数组最后的那个值填充。我们来看下代码 1public static int fibonacciSearch(int[] array, int key) { 2 if (array == null || array.length == 0) 3 return -1; 4 int length = array.length; 5 int k = 0; 6 while (length > fibonacci(k) - 1 || fibonacci(k) - 1 < 5) { 7 k++; 8 } 9 int[] fb = makeFbArray(fibonacci(k) - 1); 10 int[] temp = Arrays.copyOf(array, fb[k] - 1); 11 for (int i = length; i < temp.length; i++) { 12 temp[i] = array[length - 1];//用原数组最后的值填充 13 } 14 int low = 0; 15 int hight = length - 1; 16 while (low <= hight) { 17 int middle = low + fb[k - 1] - 1; 18 if (temp[middle] > key) {//要查找的值在前半部分 19 hight = middle - 1; 20 k = k - 1; 21 } else if (temp[middle] < key) {//要查找的值在后半部分 22 low = middle + 1; 23 k = k - 2; 24 } else { 25 if (middle <= hight) { 26 return middle; 27 } else { 28 return hight; 29 } 30 } 31 } 32 return -1; 33} 34 35private static int fibonacci(int n) { 36 if (n == 0 || n == 1) 37 return n; 38 return fibonacci(n - 1) + fibonacci(n - 2); 39} 40 41public static int[] makeFbArray(int length) { 42 int[] array = new int[length]; 43 array[0] = 0; 44 array[1] = 1; 45 for (int i = 2; i < length; i++) 46 array[i] = array[i - 1] + array[i - 2]; 47 return array; 48}
其实经过测试发现斐波那契查找效率并没有那么高,我们再来看一下斐波那契查找的递归实现
1public static int search(int[] array, int value) { 2 if (array == null || array.length == 0) return -1; 3 int length = array.length; 4 int k = 0; 5 while (length > fibonacci(k) - 1 || fibonacci(k) - 1 < 5) { 6 k++; 7 } 8 int[] fb = makeFbArray(fibonacci(k) - 1); 9 int[] temp = Arrays.copyOf(array, fb[k] - 1); 10 for (int i = length; i < temp.length; i++) { 11 temp[i] = array[length - 1];//用原数组最后的值填充 12 } 13 return fibonacciSearch(temp, fb, value, 0, length - 1, k); 14} 15 16public static int fibonacciSearch(int[] array, int[] fb, int value, int low, int hight, int k) { 17 if (value < array[low] || value > array[hight] || low > hight) return -1; 18 int middle = low + fb[k - 1] - 1; 19 if (value < array[middle]) { 20 return fibonacciSearch(array, fb, value, low, middle - 1, k - 1); 21 } else if (value > array[middle]) { 22 return fibonacciSearch(array, fb, value, middle + 1, hight, k - 2); 23 } else { 24 if (middle <= hight) { 25 return middle; 26 } else { 27 return hight; 28 } 29 } 30} 31 32private static int fibonacci(int n) { 33 if (n == 0 || n == 1) return n; 34 return fibonacci(n - 1) + fibonacci(n - 2); 35} 36 37public static int[] makeFbArray(int length) { 38 int[] array = new int[length]; 39 array[0] = 0; 40 array[1] = 1; 41 for (int i = 2; i < length; i++) array[i] = array[i - 1] + array[i - 2]; 42 return array; 43}
上面的两个斐波那契查找有一个缺点,就是数组长度必须是斐波那契数减1,否则数组就要增大,浪费空间。我们可以优化一下,不需要扩大数组的长度,当查找的位置大于原数组的长度的时候,我们让比较的值等于数组的最后一个元素即可。 1public static int fibonacciSearch1(int[] array, int key) { 2 if (array == null || array.length == 0) 3 return -1; 4 int length = array.length; 5 int k = 0; 6 while (length > fibonacci(k) - 1 || fibonacci(k) - 1 < 5) { 7 k++; 8 } 9 int[] fb = makeFbArray(fibonacci(k) - 1); 10 int low = 0; 11 int hight = length - 1; 12 while (low <= hight) { 13 int middle = low + fb[k - 1] - 1; 14 int midvalue; 15 if (middle >= length) 16 midvalue = array[length - 1]; 17 else 18 midvalue = array[middle]; 19 if (midvalue > key) {//要查找的值在前半部分 20 hight = middle - 1; 21 k = k - 1; 22 } else if (midvalue < key) {//要查找的值在后半部分 23 low = middle + 1; 24 k = k - 2; 25 } else { 26 if (middle <= hight) { 27 return middle; 28 } else { 29 return hight; 30 } 31 } 32 } 33 return -1; 34}
|