斐波那契查找算法(代码实现)
具体代码如下:
//编写一个方法:用于获取斐波那契数组(我们这里就获取一个长度为20的斐波那契数组就可以了)
private static int[] fib(){
int[] arr= new int[20];
arr[0] = 1;
arr[1] = 1;
for (int i = 2; i < 20; i++) {
arr[i] = arr[i - 1] + arr[i - 2];
}
return arr;
}
/**
* 斐波那契查找算法实现
*/
public static int fibSearch(int[] arr,int findVal){
int left = 0;
int right = arr.length - 1;
int mid = 0; //存放mid的值
int[] f = fib(); //存放我们的斐波那契数组
int k = 0; //表示斐波那契分割数组的下标
//获取待斐波那契分割数组的值的下标
while(arr.length > f[k] - 1){
k++;
}
/*
因为f[k] - 1的值可能是大于arr的长度的,因此我们需要使用Arrays工具类构造一个扩容后的数组,并重新指向arr,但是这个时候扩容部分是默认值(也就是0)
*/
//这个时候要注意: 如果我们题目要求不能修改原数组,这个时候我们就不能去使用arr接收返回值,而是应该使用一个临时数组去接收返回值
arr = Arrays.copyOf(arr, f[k] - 1);
//新数组中扩容部分的值修改为原数组中最后一个位置的值
for (int i = right + 1; i < arr.length; i++) {
arr[i] = arr[right];
}
//使用while循环查找key的值
while(left <= right){
mid = left + f[k - 1] - 1;
int midVal= arr[mid];
if (findVal > midVal){ //向数组的右边查找
left = mid + 1;
//注意: 向左边查找的时候k需要-2,这个时候是因为左边长度为f[k - 2] - 1,下一次的时候mid 就应该是left + f[(k - 2) - 1] - 1,所以这里要进行一个k-=2
k -= 2;
}else if(findVal < midVal){ //向数组的左边查找
right = mid - 1;
k -= 1; //与上面同理
}else{ //找到了和findVal相同的值,但是我们要先判断一下mid有没有跑到扩容部分,也就是mid 有没有大于 right,如果没有返回mid,如果有,返回high
if(mid <= right){
return mid;
}else{
return right;
}
}
}
//如果while循环结束还是没有找到,就返回一个-1
return -1;
}
- 上面就是我们的斐波那契查找算法的实现
我们是将我们的斐波那契查找算法放置到了我们的一个自定义工具类Search中了,下面我们就给出Search类的代码:
package com.ffyc.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Search {
/**
* 线性查找
* @param nums
* @param findVal
* @return
*/
public static int linearSearch(int [] nums,int findVal){
//我们直接遍历数组,然后查找指定值
for (int i = 0; i < nums.length; i++) {
if(findVal == nums[i]){
return i;
}
}
//如果找不到就返回一个-1
return -1;
}
/**
* 二分查找(实现一: 返回一个值)
*/
public static int binarySearch(int [] arr,int left,int right,int findVal){
int mid = ((right - left)/2) + left;
System.out.println(right + "" +left);
//我们后面要多次使用到arr[mid],所以就会多次需要计算arr的mid位置的值,所以我们就需要使用一个临时变量midVal接收我们的arr[mid]
//那么接下来我们就只用使用midVal来代表arr[mid]的值,我们的midVal不用解析,我们的arr[mid]需要解析
if (left > right){
return -1;
}
/*
这个时候我们一定要将mid = arr[mid]的操作一定要在if(left > right)操作只有执行,如果left > right的时候执行 计算的mid的值会越界,
//所以我们要不然就不要执行 int midVal = arr[mid]操作了
*/
int midVal = arr[mid];
if(findVal > midVal){
return binarySearch(arr,mid+1,right,findVal);
}else if(findVal < midVal){
return binarySearch(arr,left,mid-1,findVal);
}else{
return mid;
}
}
/**
* 二分查找(实现二: 返回多个值
*/
public static List<Integer> binarySearch2(int [] arr, int left, int right, int findVal){
//这个时候我们也是使用递归实现: 所以首先我们就是要给出递归结束的条件
if (left > right){
//如果判断我们的left > right之后直接就返回一个空的集合就可以了,就表示找不到数据
return new ArrayList<Integer>();
}
int mid = (right - left)/2 + left;
int midVal = arr[mid];
//如果判断出我们的left <= right的时候这个时候就要进行判断
if (findVal > midVal) {
return binarySearch2(arr,mid + 1,right,findVal);
}else if (findVal < midVal){
return binarySearch2(arr,left,mid-1,findVal);
}else {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(mid);
//接下来就要向左和向右扫描,这个时候就要使用到一个临时变量
int temp = mid - 1;
while (arr[temp] == midVal) {
//之前我们可以做一个判断进行优化:
if (temp < 0 || arr[temp] != midVal) {
break;
}
arrayList.add(temp);
temp -= 1;
}
temp = mid + 1;
while (arr[temp] == midVal) {
if (temp > arr.length || arr[temp] != midVal) {
break;
}
arrayList.add(temp);
temp += 1;
}
return arrayList;
}
}
/**
* 插值排序算法(使用自适应的mid)
*/
//这里我们是要使用递归来实现插值排序的,所以这个时候我们的方法的形参位置一定要有int left 和 int right,因为我们递归的依据就是通过left和right进行递归的
public static int insertValSearch(int[] arr,int left,int right,int findVal){
//因为我们的插值排序是自适应的mid值,这个时候就有可能出现一个上越界或者是下越界,所以开始的时候一定要判断是否越界
if(left > right || findVal < arr[0] || findVal > arr[arr.length - 1]){
return -1;
}
int mid = left + (right - left)*((findVal - arr[left])/(arr[right] - arr[left]));
int midVal = arr[mid];
if(findVal > midVal){
return insertValSearch(arr,mid + 1,right,findVal);
}else if(findVal < midVal){
return insertValSearch(arr,left,mid - 1,findVal);
}else{
//表示找到了,此时直接返回mid即可
return mid;
}
}
//编写一个方法:用于获取斐波那契数组(我们这里就获取一个长度为20的斐波那契数组就可以了)
private static int[] fib(){
int[] arr= new int[20];
arr[0] = 1;
arr[1] = 1;
for (int i = 2; i < 20; i++) {
arr[i] = arr[i - 1] + arr[i - 2];
}
return arr;
}
/**
* 斐波那契查找算法实现
*/
public static int fibSearch(int[] arr,int findVal){
int left = 0;
int right = arr.length - 1;
int mid = 0; //存放mid的值
int[] f = fib(); //存放我们的斐波那契数组
int k = 0; //表示斐波那契分割数组的下标
//获取待斐波那契分割数组的值的下标
while(arr.length > f[k] - 1){
k++;
}
/*
因为f[k] - 1的值可能是大于arr的长度的,因此我们需要使用Arrays工具类构造一个扩容后的数组,并重新指向arr,但是这个时候扩容部分是默认值(也就是0)
*/
//这个时候要注意: 如果我们题目要求不能修改原数组,这个时候我们就不能去使用arr接收返回值,而是应该使用一个临时数组去接收返回值
arr = Arrays.copyOf(arr, f[k] - 1);
//新数组中扩容部分的值修改为原数组中最后一个位置的值
for (int i = right + 1; i < arr.length; i++) {
arr[i] = arr[right];
}
//使用while循环查找key的值
while(left <= right){
mid = left + f[k - 1] - 1;
int midVal= arr[mid];
if (findVal > midVal){ //向数组的右边查找
left = mid + 1;
//注意: 向左边查找的时候k需要-2,这个时候是因为左边长度为f[k - 2] - 1,下一次的时候mid 就应该是left + f[(k - 2) - 1] - 1,所以这里要进行一个k-=2
k -= 2;
}else if(findVal < midVal){ //向数组的左边查找
right = mid - 1;
k -= 1; //与上面同理
}else{ //找到了和findVal相同的值,但是我们要先判断一下mid有没有跑到扩容部分,也就是mid 有没有大于 right,如果没有返回mid,如果有,返回high
if(mid <= right){
return mid;
}else{
return right;
}
}
}
//如果while循环结束还是没有找到,就返回一个-1
return -1;
}
}
- 这个Search类有线性查找算法,二分查找算法,插值查找算法和我们的斐波那契查找算法
下面给出我们对斐波那契查找算法的测试:
/**
* 对斐波那契查找算法进行一个测试
*/
@Test
public void test3(){
int[] arr = {1,3,5,7,8,9,11,34,53,76,77,99,111,112,113,114,115};
int i = Search.fibSearch(arr,9);
System.out.println(i);
int i1 = Search.fibSearch(arr,1000);
System.out.println(i1);
}