python实现查找算法:顺序查找、二分查找与Hash查找

#无序表的顺序搜索
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查找)