查找算法(Python 3.7)

1.二分查找

  • 最优时间复杂度:O(1)
  • 最坏时间复杂度:O(logn)
非递归法
## 非递归
def binary_search(alist,item):
    first=0
    last=len(alist)-1
    while first<=last:
        mid=(first+last)//2
        if alist[mid]==item:
            return True
        elif item<alist[mid]:
            last=mid-1
        else:
            first=mid+1
    return False

testlist=[0, 1, 2, 8, 13, 17, 19, 32, 42]
print(binary_search(testlist,3))
print(binary_search(testlist,13))
递归法
## 递归
def binary_search(alist,item):
    ## 递归停止条件
    if len(alist)==0:
        return False
    mid=len(alist)//2
    if alist[mid]==item:
        return True
    elif item<alist[mid]:
        return binary_search(alist[:mid],item)
    else:
        return binary_search(alist[mid+1:],item)

testlist=[0, 1, 2, 8, 13, 17, 19, 32, 42]
print(binary_search(testlist,3))
print(binary_search(testlist,13))

2.哈希查找

对于无冲突的Hash表,查找时间复杂度为O(1)

哈希表(散列表)

是一种以键—值存储数据的结构,所有的元素之间没有任何关系。元素的存储位置,是利用元素的关键字通过某个函数直接计算得出的,这个一一对应的关系函数称为散列函数或Hash函数。

散列表是一种面向查找的存储结构。它最适合求解的问题是查找与给定值相等的记录。但是对于某个关键字能对应很多记录的情况就不适用,比如查找所有的“男”性。也不适合范围查找,比如查找年龄20~30之间的人。排序、最大、最小等也不合适。

因此,散列表通常用于关键字不重复的数据结构。比如python的字典数据类型。

一般散列函数都面临着冲突的问题,即两个不同的关键字通过散列函数计算后结果相同的现象。

散列函数的构造方法

好的散列函数:计算简单,散列地址分布均匀

  • 直接定址法
    例如取关键字的某个线性函数为散列函数:f(key) = a*key + b (a,b为常数)
  • 除留余数法(最常见之一)
    数据集合长度为m
    散列公式为:f(key) = key mod p (p<=m)
    mod—取模(求余数)
    当数据量较大时,冲突是必然的,一般会选择接近m的质数
  • 数字分析法
    抽取关键字里的数字,根据数字的特点进行地址分配
  • 平方取中法
    将关键字的数字求平方,再截取部分
  • 折叠法
    将关键字的数字分割后分别计算,再合并计算
  • 随机数法
    选择一个随机数,取关键字的随机函数值为它的散列地址。
    f(key) = random(key)
处理散列冲突
  • 开放定址法(线性探测法)
    一旦发生冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入,不管这个地址是否为后面预定的。
    线性探测带来的最大问题就是冲突的堆积。
  • 再散列函数法
    发生冲突时就换一个散列函数计算,总有一个可以把冲突解决掉,它能够使关键字不产生聚集,但相应的增加了计算的时间。
  • 链接地址法
    遇到冲突时不更换地址,而是将所有关键字为同义词的记录存储在一个链表里,在散列表中只存储同义词子表的头指针,如图:
    在这里插入图片描述
    好处是,不怕冲突多;缺点是降低了散列结构的随机存储性能。本质是用单链表结构辅助散列结构的不足。
  • 公共溢出区法
    为所有的冲突,额外开辟一块存储空间。如果相对基本表而言,冲突的数据很少的时候,使用这种方法比较合适。
    在这里插入图片描述
实现代码
class HashTable:
    def __init__(self,size):
        ## 使用list数据结构作为哈希表元素保存方法
        self.elem=[None for i in range(size)]
        self.count=size
    def hash(self,key):
        ## 散列表采用除留余数法
        return key % self.count
    def insert_hash(self,key):
        ## 求散列地址
        address=self.hash(key)
        ## 若该位置已经有数据了,发生冲突,用线性探测法
        while self.elem[address]:
            address=(address+1) % self.count
        ## 没有冲突则直接保存
        self.elem[address]=key
    def search_hash(self,key):
        star=address=self.hash(key)
        while self.elem[address]!=key:
            address=(address+1) % self.count
            ## 没有找到或循环到了开始位置
            if not self.elem[address] or address==star:
                return False
        return True
if __name__=='__main__':
    alist=[12, 67, 56, 16, 25, 37, 22, 29, 15, 47, 48, 34]
    hash_table=HashTable(12)
    for i in alist:
        hash_table.insert_hash(i)
    for i in hash_table.elem:
        if i:
            print((i, hash_table.elem.index(i)),end=" ")
    print("\n")
    print(hash_table.search_hash(15))
    print(hash_table.search_hash(33))

参考:https://www.cnblogs.com/feixuelove1009/p/6148357.html

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值