二分查找的变体 —— Fibnaccian Search

二分查找

首先来看二分查找的基础版本 (三分支版本):

template <typename T>
static int fibSearch(T *A, int lo, int hi, T const& e){
    while (lo < hi){
        int mi = (lo + hi)/2;
        if (A[mi] < e) lo = mi + 1;
        else if (A[mi] > e) hi = mi;
        else return mi;
    }
    return -1;
}

黄金分割

事实上,分治策略并未要求子向量切分点 mi 必须居中,调整前、后区域的长度,适当地加长(缩短)前(后)子向量,一个自然的方案就是按黄金分割比来确定 mi,为简化起见,不妨设向量长度为 n = fib(k)-1。对于 [0, n) 区间内的搜索而言,可以以 mi = fib(k-1) - 1 作为前后向量的切分点。如此,前后子向量的长度分别为:

  • 前(左)子向量:fib(k-1)-1
  • 后(右)子向量:fib(k)-1-(fib(k-1) - 1) - 1 = fib(k-2) - 1

于是无论朝哪个方向深入,新向量的长度形式上仍然是某个 Fibonacci 数减一,故这一处理手法可以反复套用。直至命中或区间搜索至零而终止。

template 
static int fibSearch(T *A, int lo, int hi, T const& e){
    Fib f(hi - lo);
    while (lo < hi){
        while (hi - lo < f.get()) f.prev();
                        // 只比当前区间长度之前的 fib 数, 5 ⇒ 3, 8 ⇒ 5 
        int mi = lo + f.get() - 1; 
                        // fib(k-1) - 1
        if (A[mi] > e) hi = mi;
        else if (A[mi] < e) lo = mi + 1;
        else return mi;
    }
    return -1;
}

Fib 类的实现请见 斐波那契数列(面向对象版)

你可能感兴趣的:(算法)