12.顺序查找高效方法---二分查找、插值查找、斐波那契数列查找

/*
8.4.1 折半查找
    折半查找又称二分查找,它的前提是线性表中的记录必须是关键码有序(通常从小到大有序).
    线性表必须采用顺序存储。折半查找的基本思想是:在有序表中,取中间记录作为比较对象
    ,若给定值与中间记录关键字相等,则查找成功;若给定值小于中间记录的关键字,则在中间
    记录的左半区继续查找。不断重复上述过程,直到查找成功,或所有查找区域无记录,查找失败为止。

    假设我们有这么一个有序数列{0,1,16,24,35,47,59,62,73,88,99},除0下标外共有10个数字。
    对它进行查找是否存在62这个数。我们来看折半查找的算法是如何工作的。
*/
//折半查找
int Binary_Search(int *a, int n, int key)
{
    int low, high, mid;
    //定义最低下标为记录首位
    low = 1;
    //定义最高下标为记录末位
    high = n;
    while( low <= high)
    {
        //折半
        mid = (low + high) / 2;
        //若查找值比中值小
        if (key < a[mid])
            //最高下标调整到中位下标小一位
            high = mid - 1;         //减1和下面的加1 是比较巧妙的
        else if(key > a[mid])
            low = mid + 1;
        else
            return a[mid];
    }
    return 0;
}

/*
8.4.2 插值查找
折半查找的算法为: mid=(low+high)/2;
插值查找 将其换成: mid=low + (high-low) * (key-a[low])/(a[high]-a[low]);
Latax 插入公式
公式1
公式2

应用场景:比如要在取值范围0~10000之间100个元素从小到大均匀分布的数组中查找5,我们自然会
想到从数组下标较小的开始查找。看来我们的折半查找还是有改进空间的。
折半查找,顾名思义,存在一个参数1/2(折半),也就是mid等于最低下标low加上最高下标low的差的一半。
算法科学家们考虑的就是将这个1/2进行改进,改进为下面的计算方案:
将1/2改成了(key-a[low])/(a[high]-a[low])有什么道理呢?
 道理很简单 大大的提高了查找效率。
*/

/*
8.4.3 斐波那契查找
前面的折半查找,是从中间分,也就是说,每一次查找总是一分为二,无论数据偏大还是偏小,很多时候
未必就是最合理的做法。除了差值查找,我们再介绍一种有序查找,斐波那契查找(Fibonacci Search),
它是利用了黄金分割原理来实现的。
*/
//斐波那契查找
//a为查找的顺序数列;n为顺序数列a的长度;key为要查找的值
int Fibonacci_Search(int *a, int n, int key)
{
    int low, high, mid, i, k;
    //定义最低下标为记录首位
    low = 1;
    //定义最高下标为记录末位
    high = n;
    k = 0;
    //计算n位于斐波那契数列的位置
    while(n > F[k] - 1)     //这里的F[k] 就是之前栈中的哪个递归函数
        k++;
    //将不满的数值补全
    for (i = n; i < F[k] - 1; i++)
        a[i] = a[n];
    while(low <= high)
    {
        //计算当前分割的下标
        mid = low + F[k-1] - 1;
        //若查找记录小于当前分隔记录
        if (key < a[mid])
        {
            //最高下标调整到分割下标mid-1处
            high = mid - 1;
            //斐波那契数列下标减一位
            k = k - 1;
        }
        //若查找记录大于当前分割记录
        else if (key > a[mid])
        {
            //最低下标调整到分割下标mid+1处
            low = mid + 1;
            //斐波那契数列下标减两位
            k = k - 2;
        }
        else
        {
            if (mid <= n)
                //若相等则说明mid即为查找到的位置
                return mid;
            else
                //若mid>n说明是补全数值,返回n
                return n;
        }
    }
    return 0;
}

/*有点复杂,建议直接看书上代码的运行分析
相比于 插值查找的 mid=low + (high-low) * (key-a[low])/(a[high]-a[low]);
换为 mid = low + F[k-1] - 1;  
*/

 

你可能感兴趣的:(12.顺序查找高效方法---二分查找、插值查找、斐波那契数列查找)