参考链接
https://www.cnblogs.com/onepixel/articles/7674659.html
比较类排序-交换排序-冒泡排序
#coding:utf-8
# 冒泡排序
# 最差时间复杂度O(n^2),平均时间复杂度O(n^2)
def bubble_sort(lst):
for i in range(len(lst)-1):
for j in range(len(lst)-i-1):
if lst[j]>lst[j+1]: # 相邻数据比较大小
lst[j+1],lst[j]=lst[j],lst[j+1]
if __name__=="__main__":
lst = [1,2,2,66,4,6,7,8,-1]
bubble_sort(lst)
print(lst)
比较类排序-交换排序-快速排序
其中的partition策略常用到的算法题目见:
后续补充
#coding:utf-8
# 快速排序
# 最差时间复杂度O(n^2),平均时间复杂度O(nlogn)
# partition函数时间复杂度O(n),需要走logn趟
def partition(lst,left,right):
pivot = lst[left]
while left<right:
# 从pivot的另一端(右端)进行遍历
while left<right and lst[right]>=pivot:
right-=1
# 遇到最右边第一个比pivot小的数据,将其放在最左边的位置,实际上覆盖了左边visit过的值
lst[left]=lst[right]
# 遍历左端
while left<right and lst[left]<=pivot:
left+=1
# 遇到左边第一个大于pivot的数字,放在刚刚右边已经将值赋到左边的位置
lst[right]=lst[left]
# 达到了left==right的状态,将该位置的值=pivot
lst[left]=pivot
# 返回切分点
return left
def quick_sort(lst,left,right):
if left<right:
# 找到第一个分治点
pivot_pos = partition(lst,left,right)
# 两边分别递归排序
quick_sort(lst,left,pivot_pos-1)
quick_sort(lst,pivot_pos+1,right)
def quick_sort_main(lst):
return quick_sort(lst,0,len(lst)-1)
if __name__=="__main__":
lst = [1,2,2,66,4,6,7,8,-1]
quick_sort_main(lst)
print(lst)
比较类排序-插入排序-插入排序
#coding:utf-8
# 插入排序 适合于部分有序序列和小规模的数据
# 最差时间复杂度O(n^2),平均时间复杂度O(n^2)
# 扑克牌整理牌的方法,将无序区数据一个个插入有序区
def insert_sort(lst):
# 将左边作为有序区
for i in range(1,len(lst)):
tmp = lst[i]
idx = i-1
while idx>=0 and tmp<lst[idx]:
lst[idx+1]=lst[idx]
idx-=1
# 到此刻,要么idx=-1要么lst[idx]<=tmp,只需要将tmp放在idx+1的位置即可,因为该位置的原本值已经复制到idx+2
lst[idx+1] = tmp# 注意不要遗漏这个+1
if __name__=="__main__":
lst = [1,2,2,66,4,6,7,8,-1]
insert_sort(lst)
print(lst)
比较类排序-插入排序-shell排序
# coding:utf-8
#这个图显然是二叉树的形式,所以若集合有n个元素,那高度就为log(n)
def shell_sort(lst):
n = len(lst)
gap = n//2
while gap>0:
for i in range(gap,n):
tmp = lst[i]
j = i
while j-gap>=0 and lst[j-gap]>tmp:
lst[j] = lst[j-gap]
j-=gap
lst[j]=tmp
gap = gap//2
if __name__ == '__main__':
a = [334,5,67,345,7,345345,99,4,23,78,45,1,3453,23424]
shell_sort(a)
print(a)
比较类排序-归并排序-归并排序以及原地归并排序
分治归并思想常见算法题:后续补充
#coding:utf-8
# 归并排序
# 分割+集成
# 分割的图为二叉树的形式,若集合有n个元素,那高度就为log(n);每一层都是要放n次,所以时间复杂度为nlog(n)
# 空间复杂度O(n),原地排序的话就是O(1)
def merge(s1,s2):
# 将两个有序序列s1和s2合并成一个有序序列
c = []
i,j=0,0
m,n=len(s1),len(s2)
while i<m and j<n:
# 将s1小的一部分压入c中
while i<m and j<n and s1[i]<=s2[j]:
c.append(s1[i])
i+=1
# 将s2小的一部分压入c中
while i<m and j<n and s1[i]>s2[j]:
c.append(s2[j])
j+=1
while i<m:
c.append(s1[i])
i+=1
while j<n:
c.append(s2[j])
j+=1
return c
def merge_sort(lst):
if len(lst)<=1:
return lst
mid = len(lst)//2
left = merge_sort(lst[:mid])
right = merge_sort(lst[mid:])
return merge(left,right)
def reverse(lst,left,right):
# 字符串反转
while left<right:
lst[left],lst[right]=lst[right],lst[left]
left+=1
right-=1
def merge_inplace(lst,start1,start2,end2):
# 原地合并
i,j = start1,start2
while i<j and j<=end2:
while i<j and lst[i]<=lst[j]:
i+=1
# 该位置为左边第一个比j大的数据
while j<=end2 and lst[j]<=lst[i]:
j+=1
# 反转中间的一串
reverse(lst,i,start2-1)
reverse(lst,start2,j-1)
reverse(lst,i,j-1)
start2=j
def merge_sort_inplace(lst,left,right):
if left<right:
mid = (left+right)//2
merge_sort_inplace(lst,left,mid)
merge_sort_inplace(lst,mid+1,right)
merge_inplace(lst,left,mid+1,right)
def merge_sort_inplace_main(lst):
merge_sort_inplace(lst,0,len(lst)-1)
if __name__=="__main__":
lst = [1,2,2,66,4,6,7,8,-1]
lst = merge_sort(lst)
print(lst)
lst = [1,2,2,66,4,6,7,8,-1]
merge_sort_inplace_main(lst)
print(lst)
比较类排序-选择排序-直接选择排序
# coding=utf-8
# 时间复杂度 O(n^2)
# 不稳定
def select_sort(lst):
n = len(lst)
for i in range(n):
_min = i
for j in range(i+1,n):
if lst[j]<lst[_min]:
_min = j
if _min!=i:
lst[i],lst[_min] = lst[_min],lst[i]
if __name__=="__main__":
lst = [1,2,2,66,4,6,7,8,-1]
select_sort(lst)
print(lst)
比较类排序-选择排序-堆排序
#coding:utf-8
# 堆排序
# 平均时间复杂度O(nlogn)
# 大顶堆用来实现升序;小顶堆实现降序
# python headq是小顶堆,如果需要大顶堆 只需要将数据取负就可以
# 此处手动实现大顶堆
# 堆的结构类似完全二叉树,但是是个数组
'''
对于下标为i的元素:
parent = (i-1)//2
left = i*2+1
right = i*2+2
'''
# 调整成大顶堆
def heapify(lst,i,n):
largest = i
left = 2*i+1
right = 2*i+2
while left<n or right<n:
if left<n and lst[left]>lst[largest]:
largest = left
if right<n and lst[right]>lst[largest]:
largest = right
if largest != i:
lst[i],lst[largest] = lst[largest],lst[i]
i = largest
left = 2*i+1
right = 2*i+2
else:
break
# 堆排序
def heap_sort(lst):
# 初始化最大堆:处理每一个父节点len/2-1,从最后一个父节点开始,将父节点、他所有的子节点中的最大值交换到父节点
n = len(lst)
for i in range(n//2-1,-1,-1):
heapify(lst,i,n)
# 排序
for i in range(n-1,0,-1):
lst[0],lst[i] = lst[i],lst[0]
heapify(lst,0,i)
###################递归写法#######################
def heapify_2(lst,i,n):
largest = i
left = 2*i+1
right = 2*i+2
if left<n and lst[left]>lst[largest]:
largest = left
if right<n and lst[right]>lst[largest]:
largest = right
if largest != i:
lst[i],lst[largest] = lst[largest],lst[i]
heapify_2(lst,largest,n)
# 堆排序
def heap_sort_2(lst):
# 初始化最大堆:处理每一个父节点len/2-1,从最后一个父节点开始,将父节点、他所有的子节点中的最大值交换到父节点
n = len(lst)
for i in range(n//2-1,-1,-1):
heapify_2(lst,i,n)
# 排序
for i in range(n-1,0,-1):
lst[0],lst[i] = lst[i],lst[0]
heapify_2(lst,0,i)
if __name__=="__main__":
lst = [1,2,2,66,4,6,7,8,-1]
heap_sort(lst)
print(lst)
lst = [1,2,2,66,4,6,7,8,-1]
heap_sort_2(lst)
print(lst)
非比较类排序-桶排序
# coding:utf-8
# 桶排序与计数排序类似,但可以解决非整数的排序
'''
时间复杂度
O(n)+O((n/k)log(n/k))
当n=k的时候
O(n)
'''
def bucket_sort(lst,bucket_size=None):
# 最大值 最小值
if not bucket_size:
bucket_size = len(lst)
if len(lst)<2:
return
_min = min(lst)
_max = max(lst)
bucket_wide = (_max-_min)/bucket_size
bucket_lst = []
for x in range(bucket_size+1):
bucket_lst.append([])
# 分桶
for x in lst:
bucket_lst[int((x-_min)//bucket_wide)].append(x)
# 回写
idx = 0
for bck in bucket_lst:
bck = sorted(bck)
for x in bck:
lst[idx]=x
idx+=1
if __name__=="__main__":
lst = [1,2,2,66,4,6,7,8,-1]
bucket_sort(lst,bucket_size=2)
print(lst)
非比较类排序-计数排序
#coding:utf-8
# 计数排序(Counting Sort)是一种不比较数据大小的排序算法,是一种牺牲空间换取时间的排序算法。
# 计数排序适合数据量大且数据范围小的数据排序,如对人的年龄进行排序,对考试成绩进行排序等。
# 时间复杂度 O(n+k) 桶的数量k
def count_sort(lst):
if len(lst)<2:
return
# 最大值 最小值
_min = min(lst)
_max = max(lst)
# 建桶
bucket = [0]*(_max-_min+1)
# 计数
for x in lst:
bucket[x-_min]+=1
# 填回
idx= 0
for val,num in enumerate(bucket):
val += _min
while num>0:
lst[idx]=val
num-=1
idx+=1
if __name__=="__main__":
lst = [1,2,2,66,4,6,7,8,-1]
count_sort(lst)
print(lst)
非比较类排序-基数排序
# coding:utf-8
# 基数排序
def radix_sort(lst):
i=0
digit_num = len(str(max(lst)))
while i<digit_num:
bucket_lst = [[] for _ in range(10)]
for x in lst:
bucket_lst[int(x//(10**i))%10].append(x)
idx = 0
for bck in bucket_lst:
for x in bck:
lst[idx]=x
idx+=1
i+=1
if __name__ == '__main__':
a = [334,5,67,345,7,345345,99,4,23,78,45,1,3453,23424]
radix_sort(a)
print(a)