03=搜索算法(顺序搜索二分搜索和插值搜索)

Posted 伤心兮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了03=搜索算法(顺序搜索二分搜索和插值搜索)相关的知识,希望对你有一定的参考价值。

一、搜索

1.1 顺序搜索

  • 顾名思义,按顺序进行搜索的方式。其结构如下:

  • 时间复杂度为O( n 2 n^2 n2),一般在数据没有进行排序使用此方法

# -*- coding: utf-8 -*-  
# time: 2022/10/11 11:54  
# file: search.py  
# author: Meng  
# description:  
  
# 顺序搜索  
def order_search(item, alist):  
    # 关键词 "in" 1 in [1, 2, 3] => True    
    if item in alist:  
        print(f'item在alist中')  
    else:  
        print(f'item不在alist中')  
  

def main():  
    alist = [12, 18, 13, 16, 14, 17, 15]  
    item = 16  
    order_search(item, alist)       # => 16在alist中  
    item = 20  
    order_search(item, alist)       # => 20不在alist中  
  
  
if __name__ == '__main__':  
    main()

1.2 二分搜索

  • 二分搜索的搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。 其结构如下:

  • 时间复杂度为O( l g ( n ) lg(n) lg(n)),需要在数据排序后使用此方法

# -*- coding: utf-8 -*-  
# time: 2022/10/11 11:54  
# file: search.py  
# author: Meng  
# description:  


# 二分搜索  
def binary_search(item, alist):  
    left, right = 0, len(alist)-1  
    while left <= right:  
        mid = (left + right)//2  
        if alist[mid] < item:       # 如果查找值大于中间值  
            left = mid + 1  
        elif alist[mid] > item:     # 如果查找值小于中间值  
            right = mid - 1  
        else:                       # 如果查找值等于于中间值  
            print(f'item在alist中')  
            return  
    print(f'item不在alist中')  
  
  
def main():  
    alist = [i for i in range(12, 19)]  # => [12, 13, 14, 15, 16, 17, 18]  
    item = 16  
    binary_search(item, alist)       # => 16在alist中  
    item = 20  
    binary_search(item, alist)       # => 20不在alist中  
  
  
if __name__ == '__main__':  
    main()

1.3 插值搜索

  • 插值搜索是二分搜索的改良版本,改良的部分是每次与目标元素做比较的元素并非搜索区域内的中间元素,此元素的位置需要通过如下公式计算得出 x = i t e m − A [ l e f t ] ( r i g h t − l e f t ) A [ r i g h t ] − A [ l e f t ] x=\\fracitem-A[left](right-left)A[right]-A[left] x=A[right]A[left]itemA[left](rightleft)其中 i t e m item item为待查找的元素, l e f t left left r i g h t right right为最左边和最右边的索引。举个例子,假设有这样一个数组[0,10,20,30,40,50,60,70,80,90] ,我们可以发现,每个相邻元素的差均为 10 ,满足均匀分布。如果要查找元素 70 ,我们首先可以计算数组中小于等于 70 的元素占所有元素的比例的期望值 p= ( 70 − 0 ) ( 90 − 0 ) = 7 9 \\frac(70-0)(90-0)=\\frac79 (900)(700)=97,而数组的长度 n 我们知道等于 10 ,所以我们期望查找的索引值就为 [n×p]=7 ,对应的元素为 70 ,恰好就是我们要找的元素。这样,原本用二分法需要查找 3 次的用插值查找只用查找 1 次,大大提高了查找的效率。
  • 时间复杂度为O( l o g ( l o g   n ) log(log\\ n) log(log n)),需要在数据排序后使用此方法。不满足均匀分布的数据其效率可能不如二分法。
# 插值搜索  
def interpolation_search(item, alist):  
    left, right = 0, len(alist)-1  
    while left <= right:  
        if item > alist[-1] or item < alist[0]:  
            print(f'item不在alist中')  
            return -1  
        mid = left + int((right - left) * (item - alist[left]) / (alist[right] - alist[left]))  
        if alist[mid] < item:       # 如果查找值大于中间值  
            left = mid + 1  
        if alist[mid] > item:       # 如果查找值小于中间值  
            right = mid - 1  
        if alist[mid] == item:      # 如果查找值等于于中间值  
            print(f'item在alist中')  
            return mid  
    print(f'item不在alist中')  
  
  
def main():  
    alist = [i for i in range(8, 19, 2)]  # => [8, 10, 12, 14, 16, 18]  
    item = 16  
    interpolation_search(item, alist)       # => 16在alist中  
    item = 20  
    interpolation_search(item, alist)       # => 20不在alist中  
  
  
if __name__ == '__main__':  
    main()

1.4 参问文章

以上是关于03=搜索算法(顺序搜索二分搜索和插值搜索)的主要内容,如果未能解决你的问题,请参考以下文章

02=搜索算法(顺序搜索二分搜索和插值搜索)

常见的查找算法:插值查找

挖掘算法中的数据结构:二分搜索树(删除广度优先遍历顺序性)及 衍生算法问题

leetcode查找算法(顺序查找,二分法,斐波那契查找,插值查找,分块查找)

二分查找算法

二分搜索 O(log n) 算法在顺序列表中查找重复项?