常用排序算法Python实现
本文仅提供冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序的Python实现。
在最开始先列出上述排序算法的时间复杂度:
冒泡排序
bubbleSort()复杂度O(n^2)选择排序
selectionSort()复杂度O(n^2)插入排序
insertionSort()复杂度O(n^2)希尔排序
shellSort()复杂度O(n)与O(n^2)之间归并排序
mergeSort()复杂度O(nlog n)需要额外使用一倍的存储空间快速排序
quickSort()复杂度O(nlog n)不需要额外使用存储空间
冒泡排序
冒泡排序的思路在于对无序表进行多趟比较交换。
每趟包括了多次两两相邻比较,并将逆序(顺序)的数据项互换位置,最终能将本趟的最大项(最小项)就位。
经过n-1次比较、交换,实现整表的排序。
1 | def bubbleSort(list): |
选择排序
选择排序对冒泡排序进行了改进,保留了其基本的多趟比对思路,每趟都使当前最大项就位
但选择排序对交换进行了削减,相比起冒泡排序进行多次交换,每趟仅进行1次交换,记录最大项的所在位置,最后再跟本趟最后一项交换
1 | def selectionSort(list): |
插入排序
插入排序维持一个已排好序的子列表,其位置始终在列表的前部,然后逐步扩大这个子列表直到全表
第1趟,子列表仅包含第1个数据项,将第 2个数据项作为“新项”插入到子列表的合适位置中,这样已排序的子列表就包含了2个数据项
第2趟,再继续将第3个数据项跟前2个数据项比对,并移动比自身大的数据项,空出位置来,以便加入到子列表中
经过n-1趟比对和插入,子列表扩展到全表,排序完成
1 | def insertionSort(list): |
冒泡排序,选择排序,插入排序的时间复杂度都比较高,也比较容易理解,接下来的几个排序算法需要好好理解一下。
希尔排序
希尔排序是一种分组的插入排序算法
对无序表进行“间隔”划分子列表,每个子列表都执行插入排序
随着子列表的数量越来越少,无序表的整体越来越接近有序,从而减少整体排序的比对次数
最后一趟是标准的插入排序,但由于前面 几趟已经将列表处理到接近有序,这一趟仅需少数几次移动即可完成
上边的描述可能比较难以理解,给一个小示例作为思路就可以懂了:
1 | ''' 希尔排序思路 |
可以发现,希尔排序就是分为多个组,在每个组内进行插入排序,不同的是排序的间隔不再是1,而是同组内相邻两元素的距离gap
只是逻辑上分为多个组进行排序,并没有真的将列表拆分为多个列表
1 | # 希尔排序算法 |
归并排序
归并排序是递归算法,思路是将数据表持续分裂为两半,对两半分别进行归并排序,即先分解后合并。
也简单说一下思路好了:
1 | ''' |
看一下代码,应该很容易理解,就是一个递归。
1 | def mergeSort(list): |
快速排序
快速排序的思路是依据一个“中值”数据 项来把数据表分为两半
小于中值的一半 和大于中值的一半,然后每部分分别进行快速排序(递归)
快速排序的递归算法“递归三要素”如下
基本结束条件:数据表仅有1个数据项,自然是排好序的
缩小规模:根据“中值”,将数据表分为两半,最好情况是相等规模的两半
调用自身:将两半分别调用自身进行排序
注意:排序基本操作在分裂过程中完成!
快速排序的思路:
选定中值,将表分为两半,最好是想等规模的两半
将两半分别调用自身进行排序(排序操作在分裂过程中)
设置左右标:
左标向右移动,右标向左移动
左标一直向右移动,碰到比中值大的就停止
右标一直向左移动,碰到比中值小的就停止
然后把左右标所指的数据项交换
直到左标移动到右标的右侧,即交错,停止移动
此时右标所指的位置就是中值应处的位置
将中值和这个位置的值进行交换
此时分裂完成,左半部比中值小,右半部比中值大
1 | # 主程序 |
快速排序的算法比较绕,理解了中值应该放到什么位置,就能比较好的理解这个排序算法了。
常用排序算法Python实现