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))