![60e585a865b547fc43c5c152acf0eeb5.png](https://i-blog.csdnimg.cn/blog_migrate/29b839ff4fb80cdc0da5f0e79f78b579.jpeg)
Python数据结构(七)排序算法 上
上回:
本文的重点不是代码,而是带着大家分析每一个排序算法背后的思想以及使用到的数据结构。很多时候不是我们想不出算法该如何去写,而是题目并没有指定特定的数据结构,比如说同样一个一维数组排序问题,让我选择用Binary Sort Tree和用Heap,我肯定选择前者,因为它名字长(别打我!)。
一、冒泡排序
![41330ecdd016bd476e80494d2cf2f670.png](https://i-blog.csdnimg.cn/blog_migrate/dec3ba126193fa682eb4d1b8c6c62585.png)
入门必备的排序算法,非常的古老了,想当初我的C语言入门代码就是这个算法,当时交作业的时候在网上随便抄了一个上去,结果被老师发现了,一顿臭骂…...
原理请记住一个:一个有序的数组是不存在逆序对的。所谓的逆序对,比如说我们要数组元素越来越大,那么其中任何两两组成的对子(43,56)前面比后面的数值大的都是逆序对,应对方法是只要把这些逆序对调换过来即可。
def bubbleSort(array:list)->None:
flag = False
bias = 0
LENGTH_ARRAY = len(array)
while not flag:
for i in range(1,LENGTH_ARRAY-count):
if array[i-1] > array[i]:
array[i-1],array[i] = array[i],array[i-1]
flag = True
bias += 1
flag = not flag
这里设计这个flag 的目的在于检测当前数组里是否存在逆序对,如果存在至少一个逆序对,则flag就会被设置成True,再在For循环末尾被取反变成False,这样就能够保证while 的判断条件持续为真。因此,只要当前数组不存在逆序对,则while循环就会被终止,而这样也非常符合逻辑,因为如果把剩下未排序数组遍历完一遍发现没有逆序对,那就不用再遍历。
二、选择排序
![a74feb06bb3c93a7afe61bb627a9bb61.png](https://i-blog.csdnimg.cn/blog_migrate/ff86d59e8e36c777abc1b12caa4a0723.png)
整个一维数组分成两个部分,前一部分是有序数组,后一部分是无序数组,每次呢,都是从后面的无序数组部分挑选出最小的那个(时间复杂度O(n))作为前面有序数组的最后一个元素。
因为每次只能选择一个元素,而整个数组的规模是n,所以重复n次,总的时间复杂度是O(n^2)。
def selectSort(array:list)->None:
LENGTH_ARRAY = len(array)
for i in range(0,LENGTH_ARRAY-1):
minIndex = i
for j in range(i+1,LENGTH_ARRAY):
if array[minIndex] > array[j]:
minIndex = j
if minIndex != i:
array[minIndex],array[i] = array[i],array[minIndex]
稍微解释一下 为什么外层for 是到LENGTH_ARRAY-1停止。因为当我们前n-1个元素都已经是有序的时候,最后一个元素就是整个数组里最大的(这点可以明白不?)于是乎,不用排序了。
三、插入排序
![fb274a24f731ee9cc48005946ed6ea62.png](https://i-blog.csdnimg.cn/blog_migrate/c03de9214c7497b10b8767594f439999.png)
插入排序和选择排序在形式上是非常相似的,逻辑都是由“选择”+ “插入(调换)”组成。
先介绍一下插入排序和宏观思想:
假设当前遍历到第n个元素,原来数组以第n个元素为分界线分成两部分,前一部分是已经从小到大排好序的数组,第n个元素之后是未排好序的数组,在n不断向后移动的过程中,有序数组长度不断增长直到和原数组一样,此时排序结束。
插入排序的精髓: 每次迭代,都选择一个元素进行插入,选择的时间复杂度为O(1);插入的过程中根据插入的方式不同,有二分插入、线性插入,对应的时间复杂度也会不同,二分的是log(n),线性是O(n)。和选择排序相比,插入排序在插入部分耗时最多,而选择排序在选择部分耗时最多。
接下来用python实现插入排序的线性插入。
def insertionSort(array:list)->None:
for i in range(1,len(array)):
for j in range(i,0,-1):
if array[j-1] > array[j]:
array[j-1],array[j] = array[j],array[j-1]
else:
break # 无需比较
说真的,这个插入排序版本很想冒泡排序的逆过程,就像是每次都把最后一个元素一直往前怼,怼到不能再怼的位置停下来,再把下一个元素往前怼…说的不是很文雅但是意思就是这么个意思。
另外我在这个github版本里还添加了自己的insertionSort版本,那个是我第一次写insertionsort 算法,大家可以对照一下,虽然更加繁琐了,但是还挺好玩的: python 实现排序算法
总结
本节主要讲解了冒泡排序、选择排序、插入排序三种排序算法,三者都是非常古老的算法。排序算法之所以重要,是因为我们在日常coding 中如果操作的数据是在有序结构的数据上,时间复杂度是会大大减少很多的,人生本就苦短,我用算法+ python。
引用
[1] ComparisonSort