package com.itheima.security.springboot.algorithm.search;
import java.util.Arrays;
/**
* @description:
* @Author: muyi
* @CreateDate: 2020/12/2 12:00
*/
public class FibonacciSearch {
/**
* 斐波那契数组的长度
*/
private final static int FIB_ARRAY_LENGTH = 10;
/**
* 斐波那契数组的最小长度
*/
private final static int FIB_ARRAY_MIN_LENGTH = 3;
public static void main(String[] args) {
System.out.println(Arrays.toString(getFibArray()));
int[] array = {1, 5, 15, 22, 25, 31, 39, 42, 47, 49, 59, 68, 88, 88, 88, 88, 88};
System.out.println(array.length);
System.out.println(fibonacciSearch(array, 47));
System.out.println(recurseFibonacciSearch(array, getFibArray(), 47, 0, array.length - 1, 7));
}
/**
* 获取斐波那契数组
*
* @Author muyi
* @Date 12:07 2020/12/2
*/
private static int[] getFibArray() {
int[] fibArray = new int[FIB_ARRAY_LENGTH];
if (FIB_ARRAY_LENGTH < FIB_ARRAY_MIN_LENGTH) {
throw new IllegalArgumentException("斐波那契数列的最小长度为3");
}
fibArray[0] = 1;
fibArray[1] = 1;
for (int i = 2; i < FIB_ARRAY_LENGTH; i++) {
fibArray[i] = fibArray[i - 1] + fibArray[i - 2];
}
return fibArray;
}
/**
* 斐波那契查找(非递归)
*
* @param array 待查找的数组
* @param key 查找的关键字
* @return int 关键字在数组的位置,未查找到,返回-1
* @Author muyi
* @Date 12:08 2020/12/2
*/
public static int fibonacciSearch(int[] array, int key) {
if (array == null || array.length == 0) {
return -1;
}
int length = array.length;
// 制造一个长度为10的斐波数列,要特别明确:这里面的数据是索引值!!!!
int[] fb = getFibArray();
int k = 0;
// 找出数组的长度在斐波数列(减1)中的位置,将决定如何拆分!
while (length > fb[k] - 1) {
// 此时K的值为斐波那契数列中大于【数组长度的最小值】所在的索引值
k++;
}
// 构造一个长度为fb[k] - 1的新数列,构造查询的中间数组
int[] temp = Arrays.copyOf(array, fb[k]);
// 获取数组最后一个位置的元素值,用该值对新数列length以后的元素进行填充
int arrayLastValue = array[length - 1];
for (int i = length; i < temp.length; i++) {
temp[i] = arrayLastValue;
}
// 刚开始是在整个中间数组中进行茶渣,即对查询数组进行黄金分割
int low = 0;
int high = array.length - 1;
while (low <= high) {
/**
* 从 temp 数组中找黄金分割点,
* 黄金分隔点即是斐波那契数组的前一索引位置的数字
* 斐波那契的特点:f[k] = f[k-1] + f[k-2] ===》 f[k]-1 = f[k-1]-1 + f[k-2]-1 +1
* 黄金分割点的值为 f[k-1] -1,正常黄金分割点的值应该是f[k-1],但这里代表的是数组的索引,从0开始,故这里需要对其进行-1操作
* low是作为获取黄金分隔点的基准值
*/
int middle = low + fb[k - 1] - 1;
// 如果黄金分隔点的数大于关键字,那继续从黄金分割点之前查找
if (temp[middle] > key) {
high = middle - 1;
// 前面的元素个数是 f[k-1] 个
k--;
}
// 如果小于关键字,那继续从黄金分割点之后查找
else if (temp[middle] < key) {
low = middle + 1;
// 后面的元素个数是 f[k-2] 个
k -= 2;
} else {
// 若相等则说明mid即为查找到的位置
if (middle <= high) {
return middle;
}
// middle的值已经大于high,进入扩展数组的填充部分,即最后一个数就是要查找的数。
else {
return high;
}
}
}
return -1;
}
/**
* 斐波那契查找(递归方式)
*
* @param array 待查找的数组
* @param fibArray 斐波那契数组
* @param key 关键字
* @param low 低索引值
* @param high 高索引值
* @param index 索引值,即查找数组最大长度所对应的斐波那契数组中数据的索引值
* @return int 关键字在数组的位置,未查找到,返回-1
* @Author muyi
* @Date 14:32 2020/12/2
*/
public static int recurseFibonacciSearch(int[] array, int[] fibArray, int key, int low, int high, int index) {
/**
* key < array[low]:小于最小值
* key > array[high]:大于最大值
* low > high:遍历整个数组均未找到元素,退出
*/
if (array == null || array.length == 0 || key < array[low] || key > array[high] || low > high) {
return -1;
}
int middle = low + fibArray[index - 1] - 1;
if (key < array[middle]) {
// 如果小于关键字,在黄金分隔点之前查找
return recurseFibonacciSearch(array, fibArray, key, low, middle - 1, index - 1);
} else if (key > array[middle]) {
// 如果大于关键字,在黄金分割点之后查找
return recurseFibonacciSearch(array, fibArray, key, middle + 1, high, index - 2);
} else {
// 若相等则说明 middle 即为查找到的位置
if (middle <= high) {
return middle;
// middle的值已经大于high,进入扩展数组的填充部分,即最后一个数就是要查找的数。
} else {
return high;
}
}
}
}
斐波那契查找 java代码实现(包含普通和递归两种)
最新推荐文章于 2023-01-06 22:33:31 发布