排序算法
定义:是一种能将一串数据依照特定的顺序进行排列的一种算法。
1.冒泡排序
思路:比较相邻的元素。如果第一个比第二个大,就交换他们两个。以此类推,对每一对相邻元素做相同处理,从开始第一队到结尾的最后一对。这不做完之后最后的元素就会是最大的数。然后对所有的元素进行重复以上的步骤,每次都出去最后的一个。
冒泡排序
无序的序列:[54,26,93,17,77,31,44,55,20]
第一次比较,54>26,交换:26,54, 93,17,77,31,44,55,20
第二次比较,54<93,不处理:26,54, 93,17,77,31,44,55,20
第三次比较,93>17, 交换:26,54, 17,93, 77,31,44,55,20
第四次比较,93>77, 交换:26,54, 17, 77, 93, 31,44,55,20
第五次比较,93>31, 交换:26,54, 17, 77, 31,93, 44,55,20
第六次比较,93>44, 交换:26,54, 17, 77, 31, 44,93, 55,20
第七次比较,93>55, 交换:26,54, 17, 77, 31, 44, 55,93, 20
第八次比较,93>20, 交换:26,54, 17, 77, 31, 44, 55, 20,93
小结:1、最大的数93排在了队列的末尾
2、列表的长度n = 9,我们比较了n-1次
重复上面的过程:
26, 17,54, 31, 44, 55, 20, 77,93
小结:1、比较了n-2次
2、77放在了无序列表尾部
继续:
17, 26, 31, 44, 54, 20,55, 77,93 # 比较了 n-3 ,把55放在了无序列表的尾部
17, 26, 31, 44, 20, 54,55, 77,93 # 比较了 n-4 ,把54放在了无序列表的尾部
17, 26, 31, 20, 44, 54,55, 77,93 # 比较了 n-5 ,把54放在了无序列表的尾部
17, 26, 20, 31, 44, 54,55, 77,93 # 比较了 n-6 ,把31放在了无序列表的尾部
17, 20, 26, 31, 44, 54,55, 77,93 # 比较了 n-7 ,把26放在了无序列表的尾部
17, 20, 26, 31, 44, 54,55, 77,93 # 比较了 n-8 ,得到一个有序的序列
总结:
相邻元素两两比较把最大值排在无序序列尾部这个过程,要循环n-1
代码实现:
def bubbling_order(lis):
for i in range(len(lis)-1, 0, -1):
for j in range(i):
if lis[j] > lis[j+1]:
lis[j], lis[j+1] = lis[j+1], lis[j]
return lis
listA = [32, 56, 6, 78, 44, 34, 45, 48]
print('冒泡排序:', bubbling_order(listA))
2.选择排序
思路:首先在没有排序的序列只能够找到最大(小)元素,存放到排序序列的其实位置,再从剩余未排序元素中继续寻找最大(小)元素,放到已排序序列的末尾,重复以上操作,直到所有元素均以排序完成。
选择排序
无序的序列:[54,26,93,17,77,31,44,55,20]
第一次,从无序序列中挑出一个最小值,放在有序序列的尾部:
17,54,26,93, 77,31,44,55,20
第二次,从无序序列中挑出一个最小值,放在有序序列的尾部:
17,20,54,26,93, 77,31,44,55
第三次,从无序序列中挑出一个最小值,放在有序序列的尾部:
17,20, 26,54, 93, 77,31,44,55
第四次,从无序序列中挑出一个最小值,放在有序序列的尾部:
17,20, 26, 31,54, 93, 77, 44,55
第五次,从无序序列中挑出一个最小值,放在有序序列的尾部:
17,20, 26, 31, 44,54, 93, 77, 55
第六次,从无序序列中挑出一个最小值,放在有序序列的尾部:
17,20, 26, 31, 44,54, 93, 77, 55
第七次,从无序序列中挑出一个最小值,放在有序序列的尾部:
17,20, 26, 31, 44,54, 55, 93, 77
第八次,从无序序列中挑出一个最小值,放在有序序列的尾部:
17,20, 26, 31, 44,54, 55, 77, 93
代码实现:
# 选择排序
def choice_order(lis):
n = len(lis)
for i in range(1, n):
min_index = i-1
for j in range(i, n):
if lis[j] < lis[min_index]:
min_index = j
if min_index != i-1:
lis[i-1], lis[min_index] = lis[min_index], lis[i-1]
return lis
listB = [34, 56, 89, 7, 43, 23, 73, 21]
print('选择排序:', choice_order(listB))
3.插入排序
插入排序是一种简单直观的排序算法
思路:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相对应位置并插入。
插入排序
无序的序列:[54,26,93,17,77,31,44,55,20]
第一次插入:[20,54,26,93,17,77,31,44,55]
第二次插入:[20,54,55,26,93,17,77,31,44]
第三次插入:[20,44,54,55,26,93,17,77,31]
第四次插入:[20,31,44,54,55,26,93,17,77]
第五次插入:[20,31,44,54,55,77,26,93,17]
第六次插入:[17,20,31,44,54,55,77,26,93]
第七次插入:[17,20,31,44,54,55,77, 93,26]
第八次插入:[17,20,26,31,44,54,55,77, 93]
总结:
待排序序列元素数 : n
插入的次数: n-1
代码实现:
# 插入排序
def insert_order(lis):
n = len(lis)
for i in range(1, n):
for j in range(i, 0, -1):
if lis[j] < lis[j-1]:
lis[j], lis[j-1] = lis[j-1], lis[j]
# print(lis)
return lis
listC = [12, 45, 9, 39, 18, 89, 48, 59]
print('插入排序:', insert_order(listC))
4.快速排序
思路:快速排序又称为划分交换排序,将要排序的数据分割成独立的两部分,其中一部分的所有数据逗比另外一部分所有数据都要小,然后在按照此方法对两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
快速排序
无序的序列:[54,26,93,17,77,31,44,55,20]
第一次快速排序,那第一个元素54作为基准值,进行分割:
[26,17,31,44,20,54, 93,77,55]
经过第一次分割排序,基准值左边的序列的所有元素都小于基准右边序列的所有元素
对54 左边的序列进行递归的分割:
拿26作为基准值,进行分割:
[17,20,26, 31,44,54, 93,77,55]
对26 左边的序列进行递归的分割:
拿17作为基准值,进行分割:
[17,20,26, 31,44,54, 93,77,55]
对17 右边的序列进行递归的分割:
右边序列只有一个元素20,不能在分割,返回
对26 右边的序列进行递归的分割:
拿31作为基准值,进行分割:
[17,20,26, 31,44,54, 93,77,55]
31小于44,不处理
对54 右边的序列进行递归的分割:
拿93作为基准值,进行分割:
[17,20,26, 31,44,54, 77, 55,93]
对93 右边的序列进行递归的分割:
拿77作为基准值,进行分割:
[17,20,26, 31,44,54, 55, 77,93]
接下来,把整个序列进行排序:
[17,20,26, 31,44,54, 55, 77,93]
代码实现:
# 快速排序
def quick_order(lis, start, end):
# 判断low是否小于high,如果为false直接返回
if start >= end:
return lis
mid = lis[start] # 设置基准值
low = start
high = end
while low < high:
# 如果列表后面的数比基准值大或者相等,则前移以为直到有比基准值小点的数出现
while low < high and lis[high] >= mid:
high -= 1
# 找到就把索引[high]的值赋给第[low]个元素
lis[low] = lis[high]
# 基准值列表之前的做同样处理
while low < high and lis[low] < mid:
low += 1
lis[high] = lis[low]
lis[low] = mid
quick_order(lis, start, low-1)
quick_order(lis, low+1, end)
return lis
listD = [23, 56, 5, 67, 81, 21, 41, 14]
print('快速排序:', quick_order(listD, 0, len(listD) - 1))
5.希尔排序
希尔排序是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。
思路:希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序,随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
代码实现:
# 希尔排序
def shell_order(lis):
n = len(lis)
gap = n//2 # 设置初始步长
while gap > 0:
# 按照步长进行插入排序
for i in range(gap, n):
j = i
# 进行插入排序
while j >= gap and lis[j-gap] > lis[j]:
lis[j-gap], lis[j] = lis[j], lis[j-gap]
j -= gap
gap = gap//2 # 设置新的步长 进行循环下一次
return lis
listE = [68, 34, 56, 7, 23, 75, 90, 54]
print('希尔排序:', shell_order(listE))
6.并归排序
思路:
假如我们有一个n个数的数列,下标从0到n-1
首先是拆分的过程
1 、我们按照 n//2 把这个数列分成两个小的数列
2 、把两个小数列 再按照新长度的一半 把每个小数列都分成两个更小的
3、一直这样重复,一直到每一个数列包含单个元素之后是合并排序的过程:
3、按照最后分开的两个数比较大小并合并成有序的数组
4 、对每组数据按照上次分开的结果,进行排序并合并成更大的数组
5、最后的到一个有序的数组
归并排序
无序的序列:[54,26,93,17,77,31,44,55,20]
拆分过程:
第一次拆分,n = 9 n//2 = 4
拆分结果:[54,26,93,17]和[77,31,44,55,20]
递归拆分[54,26,93,17]的部分:
n = 5 n//2 = 2
拆分结果:[54,26]和[93,17]
递归拆分[54,26]的部分:
n = 2 n//2 = 1
拆分结果:[54]和[26]
合并[54]和[26],合并的结果 [26,54]
递归拆分[93,17]的部分:
n = 2 n//2 = 1
拆分结果:[93]和[17]
合并[93]和[17],合并的结果[17, 93]
合并left=[26,54]和right=[17, 93]
创建results =[]
定义两个指针 lp=0,rp=0
比较left[lp]和right[rp] , 26>17
把17添加到results中,result.append(right[rp])
results=[17]
rp+=1 rp = 1
比较left[lp]和right[rp] , 26<93
把26添加到results中,result.append(left[lp])
results=[17,26]
lp+=1 lp =1
比较left[lp]和right[rp] , 54<93
把54添加到results中,result.append(left[lp])
results=[17,26,54]
lp+=1 lp=2
把93添加到results中,result.append(right[rp])
results=[17,26,54, 93]
返回results
递归拆分[77,31,44,55,20]的部分:
同样的道理,递归拆分合并,
得到结果: [20,31, 44, 55,77]
合并left=[17,26,54, 93]和right=[20,31, 44, 55,77]
定义results = []
定义lp=0和rp =0
比较left[lp]和right[rp] , 17<20
把17添加到results中,result.append(left[lp])
results=[17]
lp+=1 lp = 1
比较left[lp]和right[rp] , 26>20
把20添加到results中,result.append(right[rp])
results=[17,20]
rp+=1
比较left[lp]和right[rp] , 26<31
把26添加到results中,result.append(left[lp])
results=[17,20,26]
lp+=1 lp = 2
。。。。。
最终结果:
[17, 20,26, 31, 44, 54, 55,77, 93]
代码实现:
def merger_order(lis):
if len(lis) <= 1:
return lis
else:
num = len(lis)//2
left_part = merger_order(lis[:num])
right_part = merger_order(lis[num:])
return merger(left_part, right_part)
def merger(left, right):
h, r = 0, 0
result = []
while h < len(left) and r < len(right):
if left[h] < right[r]:
result.append(left[h])
h += 1
else:
result.append(right[r])
r += 1
result += left[h:]
result += right[r:]
return result
listF = [29, 4, 44, 52, 21, 42, 78, 25]
print('归并排序:', shell_order(listF))