• 查找算法之插值查找


    参考

    1. 七大查找算法 | 博客园

    主要思想

    二分查找算法是傻瓜式的将待查找序列一分为二进行查找,直到找到或者查找失败。插值查找算法,是针对待查找序列均匀分布特点、结合二分查找算法进行改进的一种自适应查找算法。

    一般的,二分查找范围一个很重要的点

    middle = (left + right)/2

    而插值查找,可根据目标元素在待查找序列中的到边界值的大小来估算到边界的距离,通过估算的距离快速缩小目标所在序列的范围,即

    middle = left + (target - a[left]) / (a[right] - a[left]) * (right - left), 当然有前提条件left < right, 不能取等号。

    先决条件

    与二分查找算法先决条件一样,可以理解为二分查找算法的优化

    1. 待查存储在顺序表中(数组,而非链表);

    2. 待查顺序表有序(递增,递减都可以,相邻元素相等也可以)

    例程

     递增序列a = [3, 6, 9, 12, 20, 25, 30 ,36],

    1. 待查找目标t=25 ,正常结果是返回5

    2. 待查找目标t=11,正常结果是查找失败(返回-1)

    网上流行的代码:乍一看是没什么问题,实际上,初始情况或者中间计算过程可能存在mid < left或者mid>right的情况。这显然不合理,因为没有在left~right正常范围进行查找。

    #error realization
    def interpolation_search(a, target):
        left = 0
        right = len(a) - 1
    
        print 'left = %d, right = %d'%(left, right)
    
        while left < right:
            middle = left + (target - a[left]) * (right - left) / (a[right] - a[left])
    
            print 'left=%d, middle=%d, right=%d'%(left, middle, right)
            if a[middle] < target:
                left = middle + 1
            elif a[middle] > target:
                right = middle - 1
            else:
                print 'sucess to find out the target'
                return middle
    
        if left == right:
            middle = left
            if a[middle]  == target:
                print 'sucess to find out the target'
                return middle
    
        print 'fail to find out the target'
        return -1
    
    
    data = [3, 6, 9, 12, 20, 25, 30,36]
    print interpolation_search(data, 25)
    print interpolation_search(data, 11) #result in endless loop

     如何解决middle超界限的问题?

    假设第n步,出现middle(n) < left(n),也就意味着a[middle(n)] < a[left(n)](因为a是递增序列);

    那么在前一步,a[middle(n-1)] > a[left(n-1)] , 导致left_n=middle(n-1) + 1 > middle(n-1),

    进而重复到middle(n) = left(n) + (target - a[left(n)]) / (a[right(n)] - a[left(n)]) * (right(n) - left(n)) < left(n);

     不妨在第n步,添加对middle(n), left(n)的判断,如果发现middle(n) < left(n)及时终止循环,返回查找失败状态。

    #modified realization
    def interpolation_search(a, target):
        left = 0
        right = len(a) - 1
    
        print 'left = %d, right = %d'%(left, right)
    
        while left < right:
            middle = left + (target - a[left]) * (right - left) / (a[right] - a[left])
    
            print 'left=%d, middle=%d, right=%d'%(left, middle, right)
    
            if middle >= left and middle <= right:
                if a[middle] < target:
                    left = middle + 1
                elif a[middle] > target:
                    right = middle - 1
                else:
                    print 'sucess to find out the target'
                    return middle
            else:
                print 'fail to find out the target'
                return -1
    
        if left == right:
            middle = left
            if a[middle]  == target:
                print 'sucess to find out the target'
                return middle
    
        print 'fail to find out the target'
        return -1
    
    
    data = [3, 6, 9, 12, 20, 25, 30,36]
    print interpolation_search(data, 25)
    print interpolation_search(data, 11)

    运行结果:

    left = 0, right = 7
    left=0, middle=4, right=7
    left=5, middle=5, right=7
    sucess to find out the target
    5
    left = 0, right = 7
    left=0, middle=1, right=7
    left=2, middle=2, right=7
    left=3, middle=2, right=7
    fail to find out the target
    -1
  • 相关阅读:
    关于屏幕点亮和熄灭你所需要知道的
    关于handler的使用和理解
    关于Android Task的学习
    Android触摸屏幕事件总结
    Android工作问题总结
    Android生命周期总结
    Android中如何在子线程更新UI
    Eclipse中启动tomcat无效,而手动启动可以访问的原因
    使用Spring进行文件加载进内存
    spring集成quartz定时器的使用
  • 原文地址:https://www.cnblogs.com/fortunely/p/9625216.html
Copyright © 2020-2023  润新知