zoukankan      html  css  js  c++  java
  • 15.顺序查找高效方法---二分查找、插值查找、斐波那契数列查找

    /*
    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;  
    */
  • 相关阅读:
    VmWare 安装 Centos
    将博客搬至CSDN
    如何快速学习新的知识
    Git使用说明--常用命令
    App 冷启动:给 Android 的 Activity 添加一个背景
    Proguard中optimize设置不当引发SimException
    完美解决android软键盘监听
    修改Activity的继承类导致程序闪退
    非技术相关的面试技巧(文章内容来自他人博客)
    Android面试题(文章内容来自他人博客)
  • 原文地址:https://www.cnblogs.com/go-ahead-wsg/p/13221176.html
Copyright © 2011-2022 走看看