美文网首页
查找算法-Python

查找算法-Python

作者: RayRaymond | 来源:发表于2020-04-20 14:32 被阅读0次

无序表查找

线性查找 O( n )

适用于线性表的顺序存储结构和链式存储结构。

#无序数列遍历查找
def unordered_search(lis,key):
    for i in range(len(lis)):
        if lis[i] == key:
            return i
    return False

assert unordered_search([1,2,3,2,1,4,5],6)==False
assert unordered_search([1,2,3,2,1,4,5],3)==2

有序表查找

二分查找 Binary Search O( log(n) )

对半分割数列

#递增数列二分查找
def binary_search(lis, key):
    l, h = 0, len(lis) - 1
    while l <= h:
        mid = (l + h)//2
        if lis[mid] == key:
            return mid
        elif lis[mid] > key:
            h = mid - 1
        elif lis[mid] < key:
            l = mid + 1
    return False

assert binary_search([1,2,3,2,1,4,5],6)==False
assert binary_search([1,2,3,2,1,4,5],4)==5

复杂度分析

  • 时间复杂度:折半搜索每次把搜索区域减少一半,时间复杂度为 O(logn)
  • 空间复杂度:O(1)

插值查找 O( log(n) )

按差值比例分割数列
对二分查找的优化,让问题规模更快的缩减

value =low + int( (high - low) * (key - list[low]) / (list[high] - list[low]) )

用此 value 成比例代替二分查找中的中间值。
但是当 key 值过大, value 有可能会超出列表范围。需要额外判定。

# 递 增数列插值查找
def interpolation(lis, key):
    l, h = 0, len(lis) - 1
    while l <= h:
        mid = l + int((h - l) * (key - lis[l]) / (lis[h] - lis[l]))
        # print(f'l {l}; h {h}; mid {mid}')
        if mid > len(lis) - 1:
            return False
        if lis[mid] == key:
            return mid
        elif lis[mid] > key:
            h = mid - 1
        elif lis[mid] < key:
            l = mid + 1
    return False

assert interpolation([1,2,3,2,1,4,5],6)==False
assert interpolation([1,2,3,2,1,4,5],4)==5

插值查找算法复杂度与二分法一致,也属于O(log(n))级别的。
其优点是,对于表内数据量较大,且关键字分布比较均匀的查找表,使用插值算法的平均性能比二分查找要好得多。
反之,对于分布极端不均匀的数据,则不适合使用插值算法。

复杂度分析

  • 时间复杂性:如果元素均匀分布,则O(log log n)),在最坏的情况下可能需要 O(n)。
  • 空间复杂度:O(1)。

斐波那契查找 O( log(2n) )

使用斐波那契数列分割要查找的数列。

斐波那契查找就是在二分查找的基础上根据斐波那契数列进行分割的。
在斐波那契数列找一个等于略大于查找表中元素个数的数F[n],将原查找表扩展为长度为F[n](如果要补充元素,
则补充重复最后一个元素,直到满足F[n]个元素),完成后进行斐波那契分割,即F[n]个元素分割为前半部分F[n-1]个元素,
后半部分F[n-2]个元素,找出要查找的元素在那一部分并递归,直到找到。

# 递增数列斐波那契查找
def fibonacci_search(lis, key):

    fibo = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,
         233, 377, 610, 987, 1597, 2584, 4181, 6765,
         10946, 17711, 28657, 46368]
    l, h = 0, len(lis) - 1

    k = 0
    while h > fibo[k] - 1:
        k += 1

    i = h
    while fibo[k] - 1 > i:
        lis.append(lis[h])
        i += 1
    print(f'k---->{k}, fibo[k]---->{fibo[k]}, ')
    print(lis)

    while l <= h:
        if k < 2:
            mid = l
        else:
            mid = l + fibo[k-1] -1
        
        print(f'low = {l}, high = {h}, mid = {mid}')
        if key < lis[mid]:
            h = mid - 1
            k -= 1
        elif key > lis[mid]:
            l = mid + 1
            k -= 2
        else:
            if mid <= h:
                return mid
            else:
                return h
    return False

assert fibonacci_search([1,2,3,2,1,4,5],6)==False
assert fibonacci_search([1,2,3,2,1,4,5,7,5,10,24,199],4)==5
#

复杂度分析

  • 最坏情况下,时间复杂度为O(log2n),且其期望复杂度也为O(log2n)。
  • 平均性能,要优于二分查找。但是在最坏情况下,比如这里如果key为1,则始终处于左侧半区查找,此时其效率要低于二分查找。

线性索引查找

索引按照结构可以分为:线性索引、树形索引和多级索引。
线性索引:将索引项的集合通过线性结构来组织,也叫索引表。
线性索引可分为:稠密索引、分块索引和倒排索引

稠密索引

在线性索引中,为数据集合中的每个记录都建立一个索引项。


稠密索引

给无序的集合,建立了一张有序的线性表。其索引项一定是按照关键码进行有序的排列。方法同上

分块索引 分块查找 O(log(m)+N/m)

给大量的无序数据集合进行分块处理,使得块内无序,块与块之间有序。

分块索引

将n个数据元素"按块有序"划分为m块(m ≤ n)。
每一块中的结点不必有序,但块与块之间必须"按块有序";
即第1块中任一元素的关键字都必须小于第2块中任一元素的关键字;
而第2块中任一元素又都必须小于第3块中的任一元素,……

流程
1、先选取各块中的最大关键字构成一个索引表;
2、查找分两个部分:先对索引表进行二分查找或顺序查找,以确定待查记录在哪一块中;
3、在已确定的块中用顺序法进行查找。

# 分块查找
def block_search(list, count, key):
    length = len(list)
    block_length = length//count
    if count * block_length != length:
        block_length += 1
    print("block_length:", block_length) # 块的多少
    for block_i in range(block_length):
        block_list = []
        for i in range(count):
            if block_i*count + i >= length:
                break
            block_list.append(list[block_i*count + i])
        result = binary_search(block_list, key)
        if result != False:
            return block_i*count + result
    return False

数据量过大,建立完整的稠密索引耗时耗力,占用资源过多;但如果不做任何排序或者索引,那么遍历的查找也无法接受,只能折中,做一定程度的排序或索引。
分块索引的效率比遍历查找的O(n)要高一些,但与二分查找的O(logn)还是要差不少。O(log(m)+N/m)

倒排索引

不是由记录来确定属性值,而是由属性值来确定记录的位置,这种被称为倒排索引。其中记录号表存储具有相同次关键字的所有记录的地址或引用(可以是指向记录的指针或该记录的主关键字)。
倒排索引是最基础的搜索引擎索引技术。


散列表 哈希查找 Hash

哈希表以键-值(key-indexed) 存储数据,只要输入待查找的key,即可查找到其对应的值

流程:
1)用给定的哈希函数构造哈希表;
2)根据选择的冲突处理方法解决地址冲突;常见的解决冲突的方法:拉链法和线性探测法。
3)在哈希表的基础上执行哈希查找。

# 哈希查找

# 取余法构造哈希表
def myHash(data, hashLength):
    return data % hashLength

# 哈希表检索数据
def searchHash(hash, hashLength, key):
    hashAddress = myHash(key, hashLength)
    #指定hashAddress存在,但并非关键值,则用开放寻址法解决
    while hash.get(hashAddress) and hash[hashAddress] != key:
        hashAddress += 1
        hashAddress = hashAddress % hashLength
    if hash.get(hashAddress) == None:
        return False
    return hashAddress - 1

# 数据插入哈希表
def insertHash(hash, hashLength, data):
    hashAddress = myHash(data, hashLength)
    # 解决冲突: key已经被占用时 开放寻址
    while(hash.get(hashAddress)):
        hashAddress += 1
        hashAddress = myHash(hashAddress,hashLength)
    hash[hashAddress] = data

def hash_search(lis,key):
    hashLength = len(lis) + 1
    hash = {}
    for i in lis:
        insertHash(hash,hashLength,i)
    #print(hash)
    return searchHash(hash, hashLength, key)

assert hash_search([1,2,3,2,1,4,5],6)==False
assert hash_search([1,2,3,2,1,4,5,7,5,10,24,199],4)==5

对于无冲突的Hash表而言,查找复杂度为O(1)(在查找前需要构建相应的Hash表)。


二叉查找树 BST 和平衡二叉树 AVL


多路查找树 B树


Reference

[1] 经典查找算法及其Python实现

[2] 七大查找算法(Python)

[3] 八个常用查找算法——python3实现

相关文章

  • python 算法开发笔记

    前言 最近看完《算法图解》对python的算法有点了解,特记录下来 算法概括 二分查找的速度比简单查找快得多 算法...

  • 算法之二分查找

    排序算法 二分查找 用于有序元素列表的查找性能: Python实现: C#实现

  • 查找算法-Python

    无序表查找 线性查找 O( n ) 适用于线性表的顺序存储结构和链式存储结构。 有序表查找 二分查找 Binary...

  • 类属性和实例属性的查找顺序

    类属性:定义在类内部的变量和方法,统称为属性。 查找顺序 - MRO 查找 Python 的属性搜索算法,在 Py...

  • 拓展

    哈希算法 Python哈希查找,构建简单哈希表http://blog.csdn.net/tingyun_say/a...

  • 和老婆重新入门开发(准备阶段)

    Python 数据结构与算法 查找 排序 其它常见算法 代码仓库的相关管理 分支git命令 数据库 关系型数据库 ...

  • 算法之二分查找

    二分查找 二分查找是著名、高效并有应用广泛的查找算法。 二分常规实现 1.循环实现 下面我用python语言实现循...

  • 算法

    一.算法基础--算法的特性 二.算法基础--算法的复杂度 三.顺序查找和二分查找 顺序查找 二分查找(前提是有序的...

  • 2018-03-30 算法 :查找简介

    世界上没有最好的算法,只有最合适的算法 查找算法:静态查找,动态查找 静态查找(一般使用线性表)的分类: 顺序查找...

  • python常用的查找算法

    常用算法 1、二分法 也成为折半查找,它是一种效率较高的查找方法。 限制: 必须是有序存储结构 内容必须按大小有序...

网友评论

      本文标题:查找算法-Python

      本文链接:https://www.haomeiwen.com/subject/jowlihtx.html