前言:排序算法是大家学习中都会学的一类经典且设计思想及其丰富的算法。这里总结几大排序算法,从设计思想上认真体会它们的异同与进化方向。
老规矩,先提出3个问题:
目录
有哪些排序算法?
借用大佬的图:
如下图,按图所示,根据是否比较类排序分为两大类,此篇文章我们就用这个分类标准来做分析,因为我们接下来要分析他们的时间复杂度,并探讨如何做到的,以及利用了什么算法思想。
他们的时间复杂度是怎么样的?
再借一张图(我查找了几篇网上的文档,有不少图片有错误或欠缺之处,请大家注意辨别,不然可能记个错误的或者也影响自己的理解):
前面一部分是比较排序,我们从平均复杂度和最坏复杂度(一会要说说为什么有些排序算法平均复杂度和最坏复杂度一样,而有些不一样)两个维度来对他们归一下类:
平均复杂度:
O(n²):插入排序,选择排序,冒泡排序;
O(nlgn):快速排序,堆排序,归并排序;以及希尔排序:O(n^m)
最坏复杂度:
O(n²):插入排序,选择排序,冒泡排序,快速排序,希尔排序;
O(nlgn):快速排序,堆排序,归并排序;
后面一部分便是非比较排序(其实个人认为也是比较排序,只是比较的方式高明了许多,当然也借助了额外的空间复杂度);
这些算法是如何设计的?(设计思想是什么样的)
看下平均复杂度,上面的几类排序方式,以O(n²)选择排序和(O(nlgn))快速排序来分析:
先想一想,怎么样能降低复杂度?尽量少进行比较呗。上面两个它们都是比较,那么为什么快速排序要快一些呢(平均)?他们的区别在哪里?没错,快速排序是按照每一个定位结果后,对当前数据的两边分别再进行递归排序。这意味着什么?意味着可以让小的数据无需再跟大的数据比较,好比我比你大,那你弟弟就不要跟我比了(我不是说你小哈),这里其实就有动态规划的思想。而选择排序则没有这么做,它就是来一个就要比一圈,就跟打擂台似的(踢馆型的)。这里注意到:插入排序的最坏时间复杂度却也是O(n²),为什么呢?因为你不能保证上来你比较的这个就是中位数,所以可能导致你只有一侧有数据,而不得不类似选择排序一样把数据全循环比较一遍。那么怎么能避免这种情况呢,看看哪个平均复杂度跟最坏是一样的,对,就是归并排序。它采用分治思想将数据不断分为小块,并在合并时利用动态规划进行插入排序,来完成尽可能的少比较(不做多余的比较)。
其他的比较排序都有类似的思想,暂不做分析了。此外比较类的排序其基本上限就是O(nlgn),这个数据跟一个东西很像:平衡二叉树,红黑树等,可利用二分的结构。二分查找的复杂度就是O(lgn),n个数那应该就是O(nlgn)了。想想他们之间的联系...
然后再看下剩下的非比较类排序算法:
这几类算法其实除了需要额外的空间外,还有一个共性:那都是他们都借助了一个数组(数组本身是带着有序属性的)。这里也不多介绍了,具体分析可以参考文章下部链接。这里再说一下我看这几个排序算法后的一点想法:我当时看到计算排序的复杂度是 n+k 后,以及基数排序的复杂度是 n * k 后,我就在想有没有一中算法可以是 n + k (这里的k指的是类似基数里的k),这样岂不是可以进一步的降低复杂度?额,这个嘛,我改天再想想看,有想到的大佬请不吝赐教。然后我又看了下桶排序,仿佛有那味了,但是它的最坏复杂度却到了 n²。(它的最好复杂度是 n 哦,比 n + k 还低)。总结下非比较类排序呢,则是统统利用了动态规划的思想,并且以空间换时间。
这篇文章考虑从算法思想上去理解排序算法的实现和进化历程,大都是个人一些思考和浅薄的分析,仅供参考,更多内容可查阅资料和查看分享链接(第一个链接有动图演示,非常适合对排序有些晕头的同学们从更直观的角度去学习)。
参考链接: