插值查找

在介绍插值查找之前,首先考虑一个问题,为什么二分查找算法中一定是折半,而不是折四分之一,或者折更多呢?
打个比方,在英文字典里面查“apple”,你下意识翻开字典是翻前面的书页还是后面的书页呢?如果再查“zoo”,又该怎么查呢?很显然,这两个单词绝对不会从中间开始查起,而是有一定目的地从前或从后开始查;
同样地,比如要在取值范围1~10000之间100个元素从小到大均匀分布的数组中查找5,我们自然会考虑从数组下标较小的开始查找;
经过以上分析,二分查找这种查找方式,不是自适应的(也就是傻瓜式的),二分查找中查找点计算如下:
mid = (low + high)/2 = low + 1/2 * (high - low);
通过类比,可以将查找的点改进为如下:
mid = low + ((key - arr[low])/(arr[high] - arr[low])) * (high - low);
也就是将上述的比例参数1/2改进为自适应的,根据关键字在整个有序表中所处的位置,让mid值的变化更靠近关键字key,这样也就间接地减少了比较次数;

基本思想:基于二分查找算法,将查找点的选择改进为自适应选择,可以提高查找效率。当然,插值查找也属于有序查找。

注:对于表长较大,而关键字分布又比较均匀的查找表来说,插值查找算法的平均性能比二分查找算法要好得多。

复杂度分析:时间复杂度O(log2^(log2^n))。

代码示例:
public class Test {

public static void main(String[] args) {
        
        int[] arr = {1, 2, 3, 6, 8, 9};
        System.out.println(binary_Search(arr, 8));
    }
    public static int binary_Search(int[] arr, int num) {
        int high = arr.length - 1;
        int low = 0;
        int mid;
        while(low < high) {
            mid = low + ((num - arr[low])/(arr[high] - arr[low])) * (high - low);
            if(arr[mid] > num) {
                high = mid - 1;
            } else if (arr[mid] < num) {
                low = mid + 1;
            } else {
                return mid;
            }
        }
        return -1;
    }
}

原文地址:https://www.cnblogs.com/yuanfei1110111/p/10205065.html

时间: 2024-10-24 15:55:12

插值查找的相关文章

数据结构之--插值查找

数据结构之--插值查找 定义:插值查找就是把要查找的关键字key与查找表中最大和最小记录的关键字比较后的查找方法,其核心就在于插值的计算公式(key-a[low])/(a[high]-a[low]) 图解: 时间复杂度:只是把折半的算法由mid=(low+high)/2变为了(mid=low+(high-low)*(key-a[low])/(a[high]-a[low])),所以时间复杂度还是为与普通折半查找一样为:O(logn). #include<stdio.h> int Binary_S

二分查找法以及拉格朗日插值查找法

不管是二分查找法还是拉格朗日法,必须先排序,否则无法使用. 插值查找发速度比二分查找法要快 插值查找法,数据均匀是1次找到,不均匀是多次,即使这样这样它也是快于二分的. 那个1.0挺重要的一个技巧,将那个比例变成实数. #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include <stdlib.h> #define N 1024 void search(int a[N],int num) { int tou = 0; int

9.18 内存区域 全局变量 线程 插值查找 位域 栈的实现

栈区可以修改默认大小配置: 栈区默认的大小是1M,在vs2013中可以修改. 堆区和栈区的地址区别: 栈是连续的,向上增长,地址越来越小.类似数组. 堆是链接的,向下增长,地址越来越大.类似链表. 栈区   高地址到低地址 堆区   低地址到高地址 #include <stdio.h> #include <stdlib.h> int main() { int a = 1, b = 2; printf("%p,%p\n", &a, &b); //a

(java)有序表查找——折半查找,插值查找,斐波那契查找

有序表查找 /* 主函数 */ public class OrderTableSearch { public static void main(String[] args) { int [] a= {0,1,16,24,35,47,59,62,73,88,99}; System.out.println(FibonacciSearch(a, 10, 88)); System.out.println(InsertKeySearch(a, 10, 88)); System.out.println(Bi

数据结构(九) 查找表的顺序查找、折半查找、插值查找以及Fibonacci查找

今天这篇博客就聊聊几种常见的查找算法,当然本篇博客只是涉及了部分查找算法,接下来的几篇博客中都将会介绍关于查找的相关内容.本篇博客主要介绍查找表的顺序查找.折半查找.插值查找以及Fibonacci查找.本篇博客会给出相应查找算法的示意图以及相关代码,并且给出相应的测试用例.当然本篇博客依然会使用面向对象语言Swift来实现相应的Demo,并且会在github上进行相关Demo的分享. 查找在生活中是比较常见的,本篇博客所涉及的这几种查找都是基于线性结构的查找.也就是说我们的查找表是一个线性表,我

看数据结构写代码(53) 静态查找表(线性查找,二分查找,斐波那契查找,插值查找)

查找定义:根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素(或记录). 查找表分类:静态查找表和动态查找表. 静态查找表:只查找,而不进行插入,删除. 动态查找表:在查找过程中同时插入查找表中不存在的数据元素,或者从查找表中删除已经存在的某个数据元素. 静态表的 查找 大致 四种 算法: 线性查找,二分查找,斐波那契查找和插值查找. 其中 在线性查找之前,对表 无要求.对于 其余三种 需要 在查找之前 排序.插值查找 除了 需要 排序,还需要 均匀分布. 下面 给出代码: 线性查

基础算法-查找:插值查找

算法描述 先来看一个实际问题:我们在一本英汉字典中寻找单词“worst”,我们决不会仿照对半查找(或Fibonacci查找)那样,先查找字典中间的元素,然后查找字典四分之三处的元素等等. 事实上,我们是在所期望的地址(在字典的很靠后的地方)附近开始查找的,我们称这样的查找为插值查找. 可见,插值查找不同于前面讨论的几种查找算法,前面介绍的查找算法是基于严格比较的,即假定我们对线性表中元素的分布一无所知(或称没有启发式信息). 然而实际中,很多查找问题所涉及的表满足某些统计的特点. 插值查找在实际

插值查找C++

和上一篇折半查找很类似,只有四则运算不一样,思想类似. 只是在插值查找的过程中,考虑了查找键的值. #include <iostream> using namespace std; //需要有序数组,最好是均匀分布的. int binary_search(int *A,int n,int key) { int left=0,right=n-1; while(left<=right) { int mid= left + (int)(1.0*(key-A[left]))/(A[right]-

快速排序 and 拉格朗日插值查找

private static void QuictSort(int[] zu, int left, int right) { if (left < right) { int i = 0; int j = right - 1; int mid = zu[(left + right) / 2]; while (true) { while (i<right && zu[i]<mid) { i++; } while (j > left && zu[j] &g