基本思想:也是二分查找的一种提升算法,通过运用黄金比例的概念在数列中选择查找点进行查找,提高查找效率。同样地,斐波那契查找也属于一种有序查找算法。

相对于折半查找,一般将待比较的key值与第mid=(low+high)/2位置的元素比较,比较结果分三种情况:
  1)相等,mid位置的元素即为所求
  2)>,low=mid+1;

3)<,high=mid-1。

  斐波那契查找与折半查找很相似,他是根据斐波那契序列的特点对有序表进行分割的。他要求开始表中记录的个数为某个斐波那契数小1,及n=F(k)-1;

开始将k值与第F(k-1)位置的记录进行比较(及mid=low+F(k-1)-1),比较结果也分为三种

  1)相等,mid位置的元素即为所求

  2)>,low=mid+1,k-=2;

  说明:low=mid+1说明待查找的元素在[mid+1,high]范围内,k-=2 说明范围[mid+1,high]内的元素个数为n-(F(k-1))= Fk-1-F(k-1)=Fk-F(k-1)-1=F(k-2)-1个,所以可以递归的应用斐波那契查找。

  3)<,high=mid-1,k-=1。

  说明:low=mid+1说明待查找的元素在[low,mid-1]范围内,k-=1 说明范围[low,mid-1]内的元素个数为F(k-1)-1个,所以可以递归 的应用斐波那契查找。

时间复杂度:O(

java输出斐波那契第n项_斐波那契查找

)

代码实现:

/*
 *----- 斐波那契查找------
 * 1.斐波那契实在二分查找基础上,用斐波那契数列来进行分割
 * 2.在斐波那契数列上找一个略大于查找元素表个数的值f(n)
 * 3.将查找元素表个数扩充到f(n) 如果要补充元素用最后一个元素补充
 * 4.完成后对f(n)个元素进行斐波那契分割,即分割成 前面f(n-1)个元素,后面f(n-2)个元素
 * 5.对要查找元素的那个部分进行递归 
 * 6.就平均性能而言 优于折半查找 但是若一直在左边长半区查找则低于折半查找
 * */
public class FibonacciSearch {
    private static int maxsize=20;

    //生成斐波那契数列
    public static int[] fibonacci() {
        int[] f=new int[maxsize];
        f[0]=1;
        f[1]=1;
        for (int i = 2; i < maxsize; i++) {
            f[i]=f[i-1]+f[i-2];
        }
        return f;
    }

    //查找
    public static int search(int[] a,int key) {
        int low=0;
        int high=a.length-1;
        int k=0; //斐波那契分割数值下标
        int mid=0;
        int f[]=fibonacci(); //获得斐波那契数列
        //获得斐波那契分割数值下标
        while (high>f[k]-1) {
            k++;
        }

        //利用Java工具类Arrays 构造新数组并指向 数组 a[]
        int[] temp=Arrays.copyOf(a, f[k]);

        //对新构造的数组进行 元素补充
        for (int i = high+1; i < temp.length; i++) {
            temp[i]=a[high];
        }

        while (low<=high) {
            //由于前面部分有f[k-1]个元素
            mid=low+f[k-1]-1;
            if (key<temp[mid]) {//关键字小于切割位置元素 继续在前部分查找
                high=mid-1;
                /*全部元素=前部元素+后部元素
                 * f[k]=f[k-1]+f[k-2]
                 * 因为前部有f[k-1]个元素,所以可以继续拆分f[k-1]=f[k-2]+f[k-3]
                 * 即在f[k-1]的前部继续查找 所以k--
                 * 即下次循环 mid=f[k-1-1]-1
                 * */
                k--;
            }
            else if (key>temp[mid]) {//关键字大于切个位置元素 则查找后半部分
                low=mid+1;
                /*全部元素=前部元素+后部元素
                 * f[k]=f[k-1]+f[k-2]
                 * 因为后部有f[k-2]个元素,所以可以继续拆分f[k-2]=f[k-3]+f[k-4]
                 * 即在f[k-2]的前部继续查找 所以k-=2
                 * 即下次循环 mid=f[k-1-2]-1
                 * */
                k-=2;
            }
            else {
                if (mid<=high) {
                    return mid;
                }
                else {
                    return high;
                }
            }
        }
        return -1;
    }
    public static void main(String[] args) {
        int [] a= {1,3,5,7,9,11,12};
        int i=search(a, 5);
        System.out.println("5在:"+(i+1));
        int j=search(a, 12);
        System.out.println("12在:"+(j+1));
    }

}