代码来源于北京大学的数据结构与算法课(Python版),注释为本人自己加上的,可供学习使用,不可用于商业转载,有错误烦请指出,感谢~
目录
二分查找
普通版
# 二分查找
def binarySearch(alist, item):
first = 0 # 查找范围第一项的下标
last = len(alist)-1 # 查找范围最后一项的下标
found = False
while first<=last and not found:
midpoint = (first + last)//2 # 中间项下标
# 若列表alist的中间项与查找项item相等,则查找成功,found置为True
# 否则就需要缩小比对范围,分为两种情况:
# 1.查找项比中间项小,说明查找项在前半部分,更改last
# 2.查找项比中间项大,说明查找项在后半部分,更改first
if alist[midpoint] == item:
found = True
else:
if item < alist[midpoint]:
last = midpoint-1
else:
first = midpoint+1
return found
testlist = [0, 1, 2, 8, 13, 17, 19, 32, 42,]
print(binarySearch(testlist, 3))
print(binarySearch(testlist, 13))
输出:
False
True
递归版
# 递归的二分查找
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]:
return binarySearch(alist[:midpoint],item)
else:
return binarySearch(alist[midpoint+1:],item)
testlist = [0, 1, 2, 8, 13, 17, 19, 32, 42,]
print(binarySearch(testlist, 3))
print(binarySearch(testlist, 13))
输出:
False
True
冒泡排序
普通版
# 冒泡排序
def bubbleSort(alist):
for passnum in range(len(alist)-1,0,-1): # passnum从n-1开始,一直减到1,总共进行n-1趟排序
for i in range(passnum): # i从0开始,一直到(passnum-1),包括了这一趟比较的范围
# 对第i项和相邻的第i+1进行比较
# 如果是逆序的,就交换
if alist[i]>alist[i+1]:
temp = alist[i]
alist[i] = alist[i+1]
alist[i+1] = temp
alist = [10,1,35,61,89,36,55]
#alist = [54,26,93,17,77,31,44,55,20]
bubbleSort(alist)
print(alist)
输出:
[1, 10, 35, 36, 55, 61, 89]
加了是否发生交换的监测
def shortBubbleSort(alist):
exchanges = True # 通过exchanges监测每趟比对是否发生过交换
passnum = len(alist)-1 # passnum从n-1开始
while passnum > 0 and exchanges: # 当还未完成n-1趟排序 且 上一趟排序发生了交换,则继续下一趟排序
# 每趟排序首先将exchanges置为False,只要发生了交换就将其置为True
exchanges = False
for i in range(passnum):
if alist[i]>alist[i+1]:
exchanges = True
temp = alist[i]
alist[i] = alist[i+1]
alist[i+1] = temp
passnum = passnum-1
alist=[20,30,40,90,50,60,70,80,100,110]
shortBubbleSort(alist)
print(alist)
输出:
[20, 30, 40, 50, 60, 70, 80, 90, 100, 110]
选择排序
def selectionSort(alist):
for fillslot in range(len(alist)-1,0,-1): # fillslot从n-1开始,一直减到1,总共进行n-1趟排序
positionOfMax=0 # 用于记录当前最大项所在的位置
for location in range(1,fillslot+1):
# 对列表中的数据进行比较,得到最大项所在的位置
if alist[location]>alist[positionOfMax]:
positionOfMax = location
# 交换位置
temp = alist[fillslot]
alist[fillslot] = alist[positionOfMax]
alist[positionOfMax] = temp
# alist = [54,26,93,17,77,31,44,55,20]
alist = [49,38,65,97,76,13,27,49]
selectionSort(alist)
print(alist)
输出:
[13, 27, 38, 49, 49, 65, 76, 97]
插入排序
def insertionSort(alist):
for index in range(1,len(alist)): # 需要将第1个数据项后的n-1个数据项插入到有序子列表,循环n-1次
currentvalue = alist[index] # 当前的插入项
position = index
# 进行比较和移动
while position>0 and alist[position-1]>currentvalue:
alist[position]=alist[position-1]
position = position-1
# 插入新项
alist[position]=currentvalue
alist = [54,26,93,17,77,31,44,55,20]
insertionSort(alist)
print(alist)
输出:
[17, 20, 26, 31, 44, 54, 55, 77, 93]
希尔排序
def shellSort(alist):
sublistcount = len(alist) // 2 # 设定初始增量为n/2
while sublistcount > 0: # 不断缩小增量,进行多趟排序
for startposition in range(sublistcount): # 每进行一次循环就对某一个子列表进行排序
# 调用gapInsertionSort函数对子列表进行排序
gapInsertionSort(alist,startposition,sublistcount)
print("增量为",sublistcount,":",alist)
sublistcount = sublistcount // 2
# 带间隔的插入排序
def gapInsertionSort(alist,start,gap):
for i in range(start+gap,len(alist),gap): # 循环的次数表示插入排序的趟数
currentvalue = alist[i] # 当前插入项的值
position = i # 当前插入项所在的位置
# 当 position-gap 位置有数据项 且 当前插入项小于 position-gap 位置的数据项,就不断地进行以下操作
# 将 position-gap 位置的数据项在子列表中向右移动一个位置
# position 指向 position-gap 位置
while position>=gap and alist[position-gap]>currentvalue:
alist[position]=alist[position-gap]
position = position-gap
alist[position]=currentvalue # 找到当前插入项的插入位置
alist = [54,26,93,17,77,31,44,55,20]
#alist = [49,38,65,97,76,13,27]
#alist = [30,20,40,90,50,60,80,70,110,100]
shellSort(alist)
print(alist)
输出:
增量为 4 : [20, 26, 44, 17, 54, 31, 93, 55, 77]
增量为 2 : [20, 17, 44, 26, 54, 31, 77, 55, 93]
增量为 1 : [17, 20, 26, 31, 44, 54, 55, 77, 93]
[17, 20, 26, 31, 44, 54, 55, 77, 93]
归并排序
普通版
def mergeSort(alist):
#print("Splitting ",alist)
if len(alist)>1: # 基本结束条件
mid = len(alist)//2
lefthalf = alist[:mid]
righthalf = alist[mid:]
# 递归调用mergeSort来对切片得到左半部分和右半部分进行排序
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)
alist = [54,26,93,17,77,31,44,55,20]
mergeSort(alist)
print(alist)
输出:
[17, 20, 26, 31, 44, 54, 55, 77, 93]
python风格版
#python风格的归并排序
def merge_sort(lst):
# 递归结束条件
if len(lst) <= 1:
return lst
# 分解问题,并递归调用
middle = len(lst) // 2
left = merge_sort(lst[:middle]) # 左半部分排序
right = merge_sort(lst[middle:]) # 右半部分排序
# 合并左右半部,完成排序
merged = []
# 只要左右部分还有数据,就进行合并
# 将左半部分的首个数据(位置为0的数据)与右半部分的首个数据进行比较
# 把更小的数据添加到merged列表中,同时把它从原来所在列表中删除(下一次比较还是从0位置开始)
while left and right:
if left[0] <= right[0]:
merged.append(left.pop(0))
else:
merged.append(right.pop(0))
# 合并未合并的部分
merged.extend(right if right else left)
# 返回结果
return merged
alist = [54, 26, 93, 17, 77, 31, 44, 55, 20]
print(merge_sort(alist))
输出:
[17, 20, 26, 31, 44, 54, 55, 77, 93]
快速排序
# 快速排序
def quickSort(alist):
quickSortHelper(alist,0,len(alist)-1)
# 指定当前排序列表开始(first)和结束(last)位置的快速排序
def quickSortHelper(alist,first,last):
if first<last: # 当列表至少包含两个数据项时,做以下操作
# 调用partition函数对当前排序列表进行拆分,返回分割点splitpoint
splitpoint = partition(alist,first,last)
# 递归调用quickSortHelper函数对拆分得到的左部分和右部分进行快速排序
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 rightmark >= leftmark and alist[rightmark] >= pivotvalue:
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 # 返回基准值位置,即分割点
alist = [54,26,93,17,77,31,44,55,20]
quickSort(alist)
print(alist)
输出:
[17, 20, 26, 31, 44, 54, 55, 77, 93]
基数排序
# 队列
class Queue:
def __init__(self):
self.items = []
def isEmpty(self): # 判空
return self.items == []
def enqueue(self, item): # 入队
self.items.insert(0,item)
def dequeue(self): # 出队
return self.items.pop()
def size(self): # 求队列元素个数
return len(self.items)
# 基数排序
def radix_sort(s):
main = Queue()
for n in s:
main.enqueue(n) # 所有数据项入队
d = len(str(max(s))) # 求出最大数据项的位数
dstr = "%%0%dd" % d # 前导零的模板,把数据项补齐为d位,位数不够的前面置0,如"%05d"表示补齐成五位数
nums = [Queue() for _ in range(10)] # 准备10个队列
for i in range(-1, -d-1, -1): # i的取值为-1到-d,代表从个位到最高位
while not main.isEmpty(): # 进行分配
n = main.dequeue()
dn = (dstr % n)[i] # 得到出队数据的第i位,转成类似"00345"[-2],即得到倒数第二位的4
nums[int(dn)].enqueue(n) # 放到对应的队列中
for k in range(10): # 从10个队列中收集到main
while not nums[k].isEmpty():
main.enqueue(nums[k].dequeue())
# 从main导出为列表
result = []
while not main.isEmpty():
result.append(main.dequeue())
return result
输出:
[20, 30, 40, 50, 60, 70, 80, 90, 100, 110]