一、需要思考的问题
排序算法最好的时间复杂度应该是O(n),也就是说从头到位遍历一遍数据就能得到排好序的数据,但这不太可能实现(除非数据本身已经有序),现有的算法的平均时间复杂度只能于趋近O(n),今天来说三个O()的算法
对于排序我们需要考虑如下几个问题:
1、是原地排序算法吗(需要创建占用的空间来辅助排序吗)?
2、是稳定排序算法吗
稳定说的是,2个相同的数字被排序时候,前后顺序是否会被改变,如果被改变就是不稳定,如不不被改变就是稳定,为什么要有这个衡量指标?
在真正软件开发中,我们要排序的往往不是单纯的整数,而是一组对象,我们需要按照对象的某个key来排序。
本文的所有截图都来自于王争老师的《算法与数据结构之美》,我只是搬运工!!!
3、时间复杂度是多少(最好、最坏、平均)?
其实大多数情况下,我们只需要记住平均的就好了,但是知道最好和最坏还是有利于提升我们对排序的选择和理解的
二、选择排序
1、原理
我觉得这个算法挺简单的,首先把整个数组分为已排序区间和未排序区间,然后每次从未排序的里面找最小的,放到已排序区间的末尾
2、思考的问题
选择排序空间复杂度为O(1),并不需要创建一个大小相同的数组来辅助排序,只需要几个额外的临时变量来存储交换时候的值,是一种原地排序算法。
是不稳定算法,比如5,8,5,2,9这样一组数据,使用选择排序算法来排序的话,第一次找到最小元素2,与第一个5交换位置,那第一个5和中间的5顺序就变了,所以就不稳定了
选择排序的最好情况时间复杂度、最坏情况和平均情况时间复杂度都为O()
这个算法基本只存在于理论上了,虽然是原地排序算法,但是时间复杂度太高,而且不稳定
三、冒泡排序
1、原理
冒泡排序只会操作相邻的两个数据。每次冒泡操作都会对相邻的两个元素进行比较,看是否满足大小关系要求。如果不满足就让它俩互换。
一次冒泡会让至少一 个元素移动到它应该在的位置,重复n次,就完成了n个数据的排序工作
2、思考的问题
冒泡排序空间复杂度为O(1),是一种原地排序算法。
是稳定算法,只要代码中设定的数值相同的话,不交换位置即可
选择排序的最好情况(数据已经有序)时间复杂度O(n),只需要遍历一次、最坏情况数据完全逆序时间复杂度都为O(),平均情况时间复杂度都为O()
为什么平均是O(),王争老师通过有序度的概念得出如下公式n*(n-1)/2=15,n=6是数据的个数,得到的15说明假设6个数值完全逆序,那所有数据需要交换的次数为15次,所以计算平均时间复杂度我们取中间值,n*(n-1)/4,如上式子的复杂度也是O(),因为只是乘了一个二分之一的常数
这个算法也基本只存在于理论上了,虽然是原地排序算法,虽然稳定,但是相同时间复杂度的插入排序,性能还是比冒泡好
四、插入排序
1、原理
插入排序原理就是拿一个新的数据,插入到已有顺序的区间中
所以将数据分为已排序区间和未排序区间,每次从未排序区间拿一个数值,到已排序区间遍历,查看应该插入到哪个位置
2、思考的问题
插入排序空间复杂度为O(1),是一种原地排序算法。
是稳定算法,只要代码中设定的数值相同的话,把数据插入到前面出现的元素后面,这样就稳定了
选择排序的最好情况(数据已经有序)时间复杂度O(n),只需要遍历一次、最坏情况数据完全逆序时间复杂度都为O(),平均情况时间复杂度都为O()
插入排序还是有不少优化空间的,比如在查找需要插入的位置的时候,已有顺序区间可以通过二分查找法来定位,甚至有插入排序的升级版--希尔排序
我就不具体讲了,大家可以看如下链接:
主要解决的问题是,很小的数字排在很后面,如果要换到前面,就需要挪动特别多数据的场景
五、为什么我们更倾向于使用插入排序算法而不是冒泡排序算法呢?
以下内容,引用于王争老师的《算法与数据结构之美》
六、总结
好了菜鸡一只,如果有疑问请大家批评指出!我一定及时rectify my mistake!
写排序这些文章的目的,其实主要还是想自己整理一遍,不然很容易忘记,其实我觉得王争老师已经考虑的非常全面了,我没什么可以添加的内容了~