#无序表的顺序搜索
def sequentialSearch(alist,item):
'''alist:待搜索的数组
item:待搜索的目标项'''
pos = 0 #从0开始搜索
found = False
'''两个退出条件:遍历完所有元素或者找到特定元素'''
while pos < len(alist) and not found:
if alist[pos] == item:
found = True
else:
pos += 1
return found
sequentialSearch([1,2,3,4,5],4)
'''顺序搜索分析:(1)item在列表中:最好情况:O(1),最差情况O(n),平均O(n/2)
(2)item不在列表中:O(n)'''
#有序表的顺序搜索
def orderedSequentialSearch(alist,item):
pos = 0
found = Fasle
stop = Fasle
while pos < len(alist) and not found and not stop:
if alist[pos] == item:
found = True
else:
if alist[pos] > item:
stop = True
else:
pos += 1
return found
'''有序表下的顺序搜索分析:(1)item在列表中:最好情况:O(1),最差情况O(n),平均O(n/2)
(2)item不在列表中:最好情况:O(1),最差情况O(n),平均O(n/2)'''
'''二分查找1:二分查找仅针对有序列表'''
def binarySearch(alist,item):
first = 0
last = len(alist) - 1 #最后一个元素的下标
found = False
while first <= last and not found:
midpoint = (first + last)//2 #确定起始中点
if alist[midpoint] == item:
found = True
else: #更新中点
if item < alist[midpoint]:
last = midpoint - 1
else:
first = midpoint + 1
return found
'''二分查找2:递归版本'''
def binarySearch(alist,item):
if len(alist) == 0:
return False:
else:
midpoint = len(alist)//2
if alist[midpoint] == item:
return True
else:
if item < alist[midpoint]:
binarySearch(alist[:midpoint],item)
else:
binarySearch(alist[midpoint+1:],item)
'''二分查找的分析:第i次比较后留下的元素个数是n/2^i,所以最差情况下,需要log2^n次方的比较,同时在递归情况下需要考虑切片操作的时间'''
'''二分查找与顺序查找的比较:从绝对数值上来看,二分查找明显优于顺序查找,但是要考虑到一点,那就是二分查找仅仅针对有序表,为了进行二分查找,排序的操作耗时也需要考虑在里面'''
'''哈希查找:1.槽数目m必须为质数
2.负载因子:项数/表的大小m
3.散列函数:3.1 余数法 项%槽数目m = 所在槽(0~(m-1))
3.2 分组求和
3.3 平方取中 *共同特点是:除数均为散列表大小m
4.冲突解决:4.1 开放寻址
(1)线性探测的开放寻址
如果一个数的散列值发现在其槽上已经有项了,就按照顺序向后直到 找到一个空槽。*在查找时增加了复杂度,如果散列值的槽上不是那个项也不能 直接返回False,而应该按顺序向后直到找到特定项或者一个空槽。而且分布不均匀
(2)扩展的线性探测:重新散列
newhashvalue = rehash(oldhashvalue) -->rehash(pos) = (pos + setvalue) % sizeoftable
不是按顺序查找下一个槽,而是跳过槽,从而更均匀的分布。
(3)链表形式
'''利用hashtable实现map数据类型'''
class HashTable:
def __init__(self):
self.size = 11 #散列表大小为11
self.slots = [None] * self.size #11个散列值槽为空
self.data = [None] * self.size #11个对应的数据槽为空
def put(self,key,data): #对传入的键值对进行散列
hashvalue = self.hashfunction(key,len(self.slots)) #初始散列值
if self.slots[hashvalue] == None: #初始散列值对应的槽为空,意味着可以填
self.slots[hashvalue] = key
self.data[hashvalue] = data
else:#如果初始散列值对应的槽不为空,要么意味着更新操作,要么进行重新散列
if self.slots[hashvalue] == key:#初始散列值就是已经是它了,就意味着更新
self.data[hashvalue] = data #replace
else: #初始散列值槽里面有别的散列值了,那么就进行重新散列
nextslot = self.rehash(hashvalue,len(self.slots))
while self.slots[nextslot] != None and self.slots[nextslot] != key: # 重新散列的槽不为空且不是存入的key,就继续散列
nextslot = self.rehash(nextslot,len(selfslots))
#散列不再冲突了
if self.slots[nexthash] == None:
self.slots[nexthash] = key
self.data[nexthash] = data
else:
self.data[nexthash] = data
def hashfunction(self,key,size): #初始散列函数
return key % size
def rehash(self,hashvalue,size): #重新散列函数
return (hashvalue + 1) % size
def get(self,key): #查找元素
startslot = self.hashfunction(key,len(self.slots)) #初始散列值
data = None
stop = False #没有找到的情况下
found = False
pos = startslot
if self.slots[pos] != None and not found and not stop:
if self.slots[pos] = key:
found = True
data = self.data[pos]
else:#重新散列呗,一个一个找
pos = self.rehash(pos,len(self.slots))
if pos == startslot: #回到初始散列值,意味着找完了所有可能的散列槽
stop = True
return data #返回data(值或者None)
def __getitem__(self,key):
return self.get(self,key)
def __setitem__(self,key,data):
self.put(self,key,data)
'''hash方法分析:我们需要分析散列表的使用的最重要的信息是负载因子λ。概念上,如果λ小,则碰撞的机会
较低,这意味着项更可能在它们所属的槽中。如果λ大,意味着表正在填满,则存在越来越多的冲突。这意味着冲突解决更困难,需要更多的比较来找到一个空槽。使用链接,增加的碰撞意味着每个链上的项数量增加。
和以前一样,我们将有一个成功的搜索结果和不成功的。对于使用具有线性探测的开放寻址的成功搜索,平均比较数大约为 1/2(1 + 1/(1-λ)) ,不成功的搜索为 1/2(1+(1/1-λ)^2 ) 如果我们使用链接,则对于成功的情况,平均比较数目是 1+λ/2,如果搜索不成功,则简单地是λ比较次数。'''
python实现查找算法:顺序查找、二分查找与Hash查找
最新推荐文章于 2021-05-19 23:25:50 发布