排序算法有段时间没看了,之前一直用伪码,尝试用python写下
文章最后有自己当初总结的快速记住各排序算法的时间复杂度、空间复杂度、稳定性、适用场景的小口诀
冒泡排序法demo(Buddle Sort)
def bubble (data):
for i in range(7,-1,-1): # 扫描次数
for j in range(i):
if data[j]>data[j+1]:#比较,交换的次数
data[j],data[j+1]=data[j+1],data[j] # 不使用临时变量,把临近两数中最小的置为前面
print('第 %d 次排序后的结果是:' %(8-i),end='') #把各次扫描后的结果打印出来
for j in range(8):
print('%3d' %data[j],end='')
print()
def showdata(data):
for i in range(8):
print('%3d'%data[i],end='')
def main():
data = [16, 25, 39, 27, 12, 8, 45, 63] # 原始数据
print('冒泡排序法的原始数据为:')
showdata(data)
print()
bubble(data)
print('排序后的结果: ')
showdata(data)
main()
打印数据为
冒泡排序法的原始数据为:
16 25 39 27 12 8 45 63
第 1 次排序后的结果是: 16 25 27 12 8 39 45 63
第 2 次排序后的结果是: 16 25 12 8 27 39 45 63
第 3 次排序后的结果是: 16 12 8 25 27 39 45 63
第 4 次排序后的结果是: 12 8 16 25 27 39 45 63
第 5 次排序后的结果是: 8 12 16 25 27 39 45 63
第 6 次排序后的结果是: 8 12 16 25 27 39 45 63
第 7 次排序后的结果是: 8 12 16 25 27 39 45 63
第 8 次排序后的结果是: 8 12 16 25 27 39 45 63
排序后的结果:
8 12 16 25 27 39 45 63
冒泡排序花费时间主要集中在固定循环n-1次的两两比较,使用岗哨来提前中断程序
def bubble (data):
for i in range(7,-1,-1):
flag=0 #flag用来判断是否执行了交换操作
for j in range(i):
if data[j+1]<data[j]:
data[j],data[j+1]=data[j+1],data[j]
flag+=1 #如果执行过交换操作,则flag不为0
if flag==0:
break
# 当执行完一次扫描就判断是否执行过交换操作,如果没有交换过数据,
# 表示此时数组已完成排序,故可直接跳出循环
print('第%d次排序'%(8-i),end='')
for j in range(8):
print('%3d' %data[j],end='')
print()
def showdata(data): #使用循环打印数据
for i in range(8):
print('%3d' %data[i],end='')
print()
def main():
data=[16,25,39,27,12,8,45,63] #原始数据
print('使用岗哨的冒泡排序法测试用的原始数据为:')
showdata(data)
bubble(data)
print('排序后的结果为:',end='')
showdata(data)
main()
打印数据为
使用岗哨的冒泡排序法测试用的原始数据为:
16 25 39 27 12 8 45 63
第1次排序 16 25 27 12 8 39 45 63
第2次排序 16 25 12 8 27 39 45 63
第3次排序 16 12 8 25 27 39 45 63
第4次排序 12 8 16 25 27 39 45 63
第5次排序 8 12 16 25 27 39 45 63
排序后的结果为: 8 12 16 25 27 39 45 63
选择排序demo(Selection Sort)
def select (data):
for i in range(7): # 只插前7个
for j in range(i+1,8): # 下标值
if data[i]>data[j]: # 取第i个位置的最大值(不包括小于i的数)
data[i],data[j]=data[j],data[i]
print('第%d次排序' % (8 - i), end='')
for j in range(8):
print('%3d' % data[j], end='')
print()
def showdata (data):
for i in range(8):
print('%3d' %data[i],end='')
print()
def main():
data=[16,25,39,27,12,8,45,63]
print('原始数据为:')
showdata(data)
select(data)
print("排序后的数据为:")
showdata(data)
main()
打印结果
原始数据为:
16 25 39 27 12 8 45 63
第8次排序 8 25 39 27 16 12 45 63
第7次排序 8 12 39 27 25 16 45 63
第6次排序 8 12 16 39 27 25 45 63
第5次排序 8 12 16 25 39 27 45 63
第4次排序 8 12 16 25 27 39 45 63
第3次排序 8 12 16 25 27 39 45 63
第2次排序 8 12 16 25 27 39 45 63
排序后的数据为:
8 12 16 25 27 39 45 63
插入排序(InsertSort)
def insert(data):
for i in range(1,8): # i作下标
tmp=data[i] #tmp临时变量,暂定其为最小
no=i-1
while no>=0 and tmp<data[no]:
data[no+1]=data[no] # 决定了其适合链表,左参数右值,小→大,右移
no-=1
data[no+1]=tmp #最小的元素放到第一个位置
print('第%d次排序' % (i), end='')
for j in range(8):
print('%3d' % data[j], end='')
print()
def showdata(data):
for i in range(8):
print('%3d' %data[i],end='') #打印数组数据
print()
def main():
data=[16,25,39,27,12,8,45,63]
print('原始数组是:')
showdata(data)
insert(data)
print('排序后的数组是:')
showdata(data)
main()
打印结果
原始数组是:
16 25 39 27 12 8 45 63
第1次排序 16 25 39 27 12 8 45 63
第2次排序 16 25 39 27 12 8 45 63
第3次排序 16 25 27 39 12 8 45 63
第4次排序 12 16 25 27 39 8 45 63
第5次排序 8 12 16 25 27 39 45 63
第6次排序 8 12 16 25 27 39 45 63
第7次排序 8 12 16 25 27 39 45 63
排序后的数组是:
8 12 16 25 27 39 45 63
希尔排序(Shell Sort)
# 随着间距值越来越小,局部有序度在不断提高,最后插排所花费的开销就小了
def shell(data,size):
k=1 #k打印计数
jmp=size//2 # " // "表示整数除法。jmp既是划分出的组数,也是间距值
while jmp != 0:
for i in range(jmp, size): # i为扫描次数 jmp 为设置间距的位移量
tmp=data[i] #tmp用来暂存数据
j=i-jmp #以j来定位比较的元素
while tmp<data[j] and j>=0: #插入排序法
data[j+jmp] = data[j] # 往后挪jmp位
j=j-jmp
data[jmp+j]=tmp # 第j位补交换值
print('第 %d 次排序过程:' %k,end='')
k+=1
showdata (data)
jmp=jmp//2 #控制循环数
def showdata(data):
for i in range(8):
print('%3d' %data[i],end='')
print()
def main():
data=[16,25,39,27,12,8,45,63]
print('原始数组是:')
showdata (data)
shell(data,8)
print('排序后的结果为:')
showdata(data)
main()
打印结果:
原始数组是:
16 25 39 27 12 8 45 63
第 1 次排序过程: 12 8 39 27 16 25 45 63
第 2 次排序过程: 12 8 16 25 39 27 45 63
第 3 次排序过程: 8 12 16 25 27 39 45 63
排序后的结果为:
8 12 16 25 27 39 45 63
归并排序法(Merge Sort)
# 合并排序法(Merge Sort)
#99999为数列1的结束数字不列入排序
list1 = [20,45,51,88,99999]
#99999为数列2的结束数字不列入排序
list2 = [98,10,23,15,99999]
list3 = []
def merge_sort():
global list1
global list2
global list3
# 先使用选择排序将两个数列排序,再进行合并
select_sort(list1, len(list1)-1)
select_sort(list2, len(list2)-1)
print('第1个数列的排序结果为: ', end = '')
for i in range(len(list1)-1):
print(list1[i], ' ', end = '')
print('\n第2个数列的排序结果为: ', end = '')
for i in range(len(list2)-1):
print(list2[i], ' ', end = '')
print()
print('=' * 50)
My_Merge(len(list1)-1, len(list2)-1)
print()
print('=' * 50)
print()
print('合并排序法的最终结果为: ', end = '')
for i in range(len(list1)+len(list2)-2):
print('%d ' % list3[i], end = '')
def select_sort(data, size):
for i in range(size-1): #
temp = i
for j in range(i+1, size):
if data[j] < data[temp]:
temp = j
data[temp], data[i] = data[i], data[temp]
def My_Merge(size1, size2):
global list1
global list2
global list3
index1 = 0
index2 = 0
for index3 in range(len(list1)+len(list2)-2):
if list1[index1] < list2[index2]: # 比较两个数列,数小的先存于合并后的数列
list3.append(list1[index1])
index1 += 1
print('\n此数字%d取自于第1个数列' % list3[index3])
else:
list3.append(list2[index2]) #新数列赋值
index2 += 1 #原数列下标
print('\n此数字%d取自于第2个数列' % list3[index3])
print('目前的合并排序结果为: ', end = '')
for i in range(index3+1):
print(list3[i], ' ', end = '')
merge_sort()
打印结果
第1个数列的排序结果为: 20 45 51 88
第2个数列的排序结果为: 10 15 23 98
==================================================
此数字10取自于第2个数列
目前的合并排序结果为: 10
此数字15取自于第2个数列
目前的合并排序结果为: 10 15
此数字20取自于第1个数列
目前的合并排序结果为: 10 15 20
此数字23取自于第2个数列
目前的合并排序结果为: 10 15 20 23
此数字45取自于第1个数列
目前的合并排序结果为: 10 15 20 23 45
此数字51取自于第1个数列
目前的合并排序结果为: 10 15 20 23 45 51
此数字88取自于第1个数列
目前的合并排序结果为: 10 15 20 23 45 51 88
此数字98取自于第2个数列
目前的合并排序结果为: 10 15 20 23 45 51 88 98
==================================================
合并排序法的最终结果为: 10 15 20 23 45 51 88 98
快速排序法(QuickSort)
import random
def inputarr(data,size):
for i in range(size):
data[i]=random.randint(1,100) # 生成指定的(1,100)的随机整数
def showdata(data,size):
for i in range(size):
print('%3d' %data[i],end='')
print()
def quick(d,size,lf,rg):
#第一项键值为d[lf]
if lf<rg: #排序数列的左边与右边
lf_idx=lf+1
while d[lf_idx]<d[lf]:
if lf_idx+1 >size:
break
lf_idx +=1
rg_idx=rg
while d[rg_idx] >d[lf]:
rg_idx -=1
while lf_idx<rg_idx:
d[lf_idx],d[rg_idx]=d[rg_idx],d[lf_idx]
lf_idx +=1
while d[lf_idx]<d[lf]:
lf_idx +=1
rg_idx -=1
while d[rg_idx] >d[lf]:
rg_idx -=1
d[lf],d[rg_idx]=d[rg_idx],d[lf]
for i in range(size):
print('%3d' %d[i],end='')
print()
quick(d,size,lf,rg_idx-1) #以rg_idx为基准点分成左右两半以递归方式
quick(d,size,rg_idx+1,rg) #分别为左右两半进行排序直至完成排序
def main():
data=[0]*100 # 初始化
size=int(input('请输入数组大小(100以下):'))
inputarr (data,size)
print('您输入的原始数据是:')
showdata (data,size)
print('排序过程如下:')
quick(data,size,0,size-1)
print('最终的排序结果为:')
showdata(data,size)
main()
输出结果
请输入数组大小(100以下):12
您输入的原始数据是:
83 67 32 88 88 50 35 13 35 40 4 14
排序过程如下:
40 67 32 14 4 50 35 13 35 83 88 88
35 35 32 14 4 13 40 50 67 83 88 88
4 13 32 14 35 35 40 50 67 83 88 88
4 13 32 14 35 35 40 50 67 83 88 88
4 13 32 14 35 35 40 50 67 83 88 88
4 13 14 32 35 35 40 50 67 83 88 88
4 13 14 32 35 35 40 50 67 83 88 88
4 13 14 32 35 35 40 50 67 83 88 88
最终的排序结果为:
4 13 14 32 35 35 40 50 67 83 88 88
堆排序(HeapSort)
def heap(data,size):
for i in range(int(size/2),0,-1):#建立堆积树节点
ad_heap(data,i,size-1)
print()
print('堆积的内容:',end='')
showdata(data,size)
print()
print("=="*30)
for i in range(size-2,0,-1): #堆积排序
data[i+1],data[1]=data[1],data[i+1]#头尾节点交换
ad_heap(data,1,i)#处理剩余节点
print('处理过程为:',end='')
showdata(data,size)
print()
def ad_heap(data,i,size):
j=2*i
tmp=data[i]
post=0
while j<=size and post==0:
if j<size:
if data[j]<data[j+1]: #找出最大节点
j+=1
if tmp>=data[j]: #若树根较大,结束比较过程
post=1
else:
data[int(j/2)]=data[j]#若树根较小,则继续比较
j=2*j
data[int(j/2)]=tmp #指定树根为父节点
def main():
data=[0,5,6,4,8,3,2,7,1] #原始数组的内容
size=9
print('原始数组为:',end='')
showdata(data,size)
heap(data,size) #建立堆积树
print("=="*30)
print('排序结果为:',end='')
showdata(data,size)
def showdata(data,size):
for i in range(1,size):
print('[%d] ' %data[i],end='')
main()
打印结果为:
原始数组为:[5] [6] [4] [8] [3] [2] [7] [1]
堆积的内容:[8] [6] [7] [5] [3] [2] [4] [1]
============================================================
处理过程为:[7] [6] [4] [5] [3] [2] [1] [8]
处理过程为:[6] [5] [4] [1] [3] [2] [7] [8]
处理过程为:[5] [3] [4] [1] [2] [6] [7] [8]
处理过程为:[4] [3] [2] [1] [5] [6] [7] [8]
处理过程为:[3] [1] [2] [4] [5] [6] [7] [8]
处理过程为:[2] [1] [3] [4] [5] [6] [7] [8]
处理过程为:[1] [2] [3] [4] [5] [6] [7] [8]
============================================================
排序结果为:[1] [2] [3] [4] [5] [6] [7] [8]
基数排序(Radix Sort)
# 基数排序法:从小到大排序
import random
def inputarr(data,size):
for i in range(size):
data[i]=random.randint(0,999) #设置 data 值最大为 3 位数
def showdata(data,size):
for i in range(size):
print('%5d' %data[i],end='')
print()
def radix(data,size):
n=1 # n为基数,从LSD
while n<=100:
tmp=[[0]*100 for row in range(10)] # 设置暂存数组,[0~9位数][数据个数],所有内容均为0
for i in range(size): # 对比所有数据
m=(data[i]//n)%10 # m为 n 位数的值,如 36 取十位数(36/10)%10=3
tmp[m][i]=data[i] # 把 data[i] 的值暂存在 tmp 中
k=0
for i in range(10):
for j in range(size):
if tmp[i][j] != 0: # 因为一开始设置 tmp ={0},故不为 0 者即为
data[k]=tmp[i][j] # data 暂存在 tmp 中的值,把 tmp 中的值放
k+=1 # 回 data[ ]里
print('经过%3d位数排序后:' %n,end='')
showdata(data,size)
n=10*n
def main():
data=[0]*100
size=int(input('请输入数组大小(100以下):'))
print('您输入的原始数据是:')
inputarr (data,size)
showdata (data,size)
radix (data,size)
main()
打印结果
请输入数组大小(100以下):15
您输入的原始数据是:
27 208 329 899 988 23 23 283 820 681 630 922 925 753 71
经过 1位数排序后: 820 630 681 71 922 23 23 283 753 925 27 208 988 329 899
经过 10位数排序后: 208 820 922 23 23 925 27 329 630 753 71 681 283 988 899
经过100位数排序后: 23 23 27 71 208 283 329 630 681 753 820 899 922 925 988
- 不稳定算法: 快些选一堆(快排、shell、选择排序、堆排),除此以外全是稳定性算法
- 选择交换,插入后移
- 最好时间复杂度(有序):直插、冒泡
- 时间复杂度O(nlogn):快堆并