搜索
二分搜索的递归实现
def BinarySearch(alist, item):
if len(alist) == 0:
return False
else:
midpoint = len(alist) // 2
if alist[midpoint] == item:
return True
else:
if alist[midpoint] < item:
return BinarySearch(alist[midpoint+1],item)
else:
return BinarySearch(alist[:midpoint],item)
二分搜索算法的时间复杂度是O(logn)
尽管二分搜索通常优于顺序搜索,但当n较小时,排序引起的额外开销可能并不划算。世纪上应该始终考虑,为了提高搜索效率,额外排序是否值得。如果排序一次后能够搜索多次,那么排序的开销不值一提。然而对于大型列表而言,只排序一次也会有昂贵的计算成本,因此从头进行顺序搜索可能是更好的选择
散列
散列函数
我们的目标是创建这样的一个散列函数:冲突数最少,计算方便,元素均匀分布与散列表中
实现映射抽象数据类型
字典是存储键-值对的数据类型,键用来查找关联的值,这个概念常常被称作映射
使用字典的一大优势是,给定一个键,能很快找到其关联的值。为了提供这种快速查找能力,需要能支持高效搜索的实现方案。虽然可以使用列表进行顺序搜索或二分搜索,但用散列表更好,这是因为散列搜索算法的时间复杂度可以达到O(1)
使用两个列表创建HashTable类,以此实现映射抽象抽象数据类型
class HashTable:
def __init__(self):
self.size = 11
self.slots = [None]*self.size
self.data = [None]*self.size
def hashfunction(self, key, size):
return key%size
def rehash(self, oldhash, size):
return (oldhash + 1)%size
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 # 替换
else:
nextslot = self.rehash(hashvalue, len(self.slots))
while self.slots[nextslot] != None and self.slots[nextslot] != key:
nextslot = self.rehash(nextslot, len(self.slots))
if self.slots[nextslot] == None:
self.slots[nextslot] = key
self.data[nextslot] = data
else:
self.data[nextslot] = data # 替换
def get(self, key):
startslot = self.hashfunction(key, len(self.slots))
data = None
stop = False
found = False
position = startslot
while self.slots[position] != None and not found and not stop:
if self.slots[position] == key:
found = True
data = self.data[position]
else:
position = self.rehash(startslot, len(self.slots))
if startslot == startslot:
stop = True
return data
def __getitem__(self,key):
return self.get(key)
def __setitem__(self, key, data):
self.put(key, data)
排序
冒泡排序
选择排序
插入排序
希尔排序
归并排序
它是递归算法,每次将一个列表一分为二。
如果列表为空或只有一个元素,那么从定义上来说它就是有序的。
如果列表不止一个元素,就将列表一分为二,并对两部分都递归调用归并排序。
当两部分都有序后,就进行归并这一基本操作。归并是指将两个较小的有序列表归并为一个有序列表的过程。
以下代码中,函数以处理基本情况开始。如果列表的长度小于或等于1,说明它已经是有序列表,因此不需要做额外的处理,如果长度大于1,则通过Python的切片操作得到左半部分和右半部分。
第二部分部分实现了对左右两个子列表进行排序合并功能(其实就是按顺序比较大小填充数据),这里注意左右两个子列表都是已经排序过的列表,代码如下
def SecondPart(alist):
mid = len(alist) // 2
lefthalf = alist[:mid]
righthalf = alist[mid:]
i = 0
j = 0
k = 0
while i < len(lefthalf) and j < len(righthalf):
if lefthalf[i] < righthalf[j]:
alist[k] = lefthalf[i]
i = i + 1
else:
alist[k] = righthalf[j]
j = j + 1
k = k + 1
while i < len(lefthalf):
alist[k] = lefthalf[i]
i = i + 1
k = k + 1
while j < len(righthalf):
alist[k] = righthalf[j]
j = j + 1
k = k + 1
check([1,5,2,3,4])
以下是整体函数实现:
def mergeSort(alist):
print("Splitting", alist)
if len(alist) > 1:
mid = len(alist) // 2
lefthalf = alist[:mid]
righthalf = alist[mid:]
mergeSort(lefthalf)
mergeSort(righthalf)
i = 0
j = 0
k = 0
while i < len(lefthalf) and j < len(righthalf):
if lefthalf[i] < righthalf[j]:
alist[k] = lefthalf[i]
i = i + 1
else:
alist[k] = righthalf[j]
j = j + 1
k = k + 1
while i < len(lefthalf):
alist[k] = lefthalf[i]
i = i + 1
k = k + 1
while j < len(righthalf):
alist[k] = righthalf[j]
j = j + 1
k = k + 1
print("Merging", alist)
mergeSort([1,3,2,4,7])
Splitting [1, 3, 2, 4, 7]
Splitting [1, 3]
Splitting [1]
Merging [1]
Splitting [3]
Merging [3]
Merging [1, 3]
Splitting [2, 4, 7]
Splitting [2]
Merging [2]
Splitting [4, 7]
Splitting [4]
Merging [4]
Splitting [7]
Merging [7]
Merging [4, 7]
Merging [2, 4, 7]
Merging [1, 2, 3, 4, 7]
快速排序
快速排序函数quickSort调用了递归函数quickSortHelper。quickSortHelper首先处理和归并排序相同的基本情况。如果列表的长度小于或等于1,说明它已经是有序列表;如果长度大于1,则进行划分操作并递归地排序。
def quickSort(alist):
quickSortHelper(alist, 0, len(alist)-1)
def quickSortHelper(alist, first, last):
if first < last:
splitpoint = partition(alist, first, last)
quickSortHelper(alist, first, splitpoint-1)
quickSortHelper(alist, splitpoint+1, last)
def partition(alist, first, last):
pivotvalue = alist[first]
leftmark = first + 1
rightmark = last
done = False
while not done:
while leftmark <= rightmark and alist[leftmark] <= pivotvalue:
leftmark = leftmark + 1
while alist[rightmark] >= pivotvalue and rightmark >= leftmark:
rightmark = rightmark - 1
if rightmark < leftmark:
done = True
else:
temp = alist[leftmark]
alist[leftmark] = alist[rightmark]
alist[rightmark] = temp
temp = alist[first]
alist[first] = alist[rightmark]
alist[rightmark] = temp
return rightmark