My Avatar

胡湘铭的博客

Coding and thinking!

斐波那契查找

2015年12月8日, 发表于 长春

如果你对本文有任何的建议或者疑问, 可以在 这里给我提 Issues, 谢谢! :)

斐波那契数列:

斐波那契查找和二分查找类似,根据斐波那契序列的特点对有序表进行分割。要求开始表中记录的个数为某个斐波那契数小1,即数组个数n=F[k]-1,即数组范围a[0]~a[F[k]-2],设点mid = F[k-1]-1,则左半部分[0,F[k-1]-2], 右半部分[F[k-1],F[k-2]]。

此时我们可以计算,左半部分长度为F[k-1]-1,右半部分长度为F[k-2]-1。 (右=F[k]-2-(F[k-1]-1)=F[k-1]+F[k-2]-2-(F[k-1]-1)=F[k-2]-1 )

左右都满足F[k]-1的形式,这就是为什么表中记录的个数为某个斐波那契数小1。当原始表不满足时,我们可以将数组A扩展到F[k]-1的长度,不足处用A[n-1]填充,再进行搜索。

所以我们有如下划分,mid是划分点:

这些都很好理解,可是mid点怎么表示呢?最初一次划分很容易取得,就是F[k-1]-1(设数组大小为F[k]-1)。 因为划分之后左右两边长度也都满足F[k]-1的形式,具体如下:

图片

依次类推。 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
void Fib( int *F)
{
    F[0] = 0;
    F[1] = 1;
    for (int i = 2; i <maxsize ; i++)
    {
        F[i]=F[i-1]+F[i-2];  
    }
}

int FibSearch(int *A,int n,int key)
{
    int *F = new int[maxsize];
    int low = 0, high = n-1;
    Fib(F);
    int k = 0;
    while ( n > F[k]-1 )
        k++;

    int *tmp = new int[F[k]-1];
    for ( int i = 0; i < n; i++)
        tmp[i] = A[i];
    for(int i = n; i < F[k]-1; i++)  
        tmp[i]=A[n-1]; //将数组A扩展到F[k]-1的长度,不足处用A[n-1]填充
    while ( low <= high )
    {
        int mid = low + F[k-1] - 1;
        if ( key < tmp[mid])
        {
            high = mid - 1;
            k -= 1;
        }
        else
        if ( key > tmp[mid])
        {
            low = mid + 1;
            k -= 2;
        }
        else
        {
            if ( mid < n )
                return mid;
            else
                return n - 1;
        }
    }
    delete[] tmp;
    return -1;
}