学习笔记 I——排序

来源:互联网 发布:淘宝评价语20字 编辑:程序博客网 时间:2024/06/10 02:54

网易面试之后,昨天又看了看排序算法,发现排序算法中看到的东西以前其实也都知道,可要立马说出来,还真是不能。现在整理一下吧。很多东西出于个人理解,纰漏之处,万一有人看到,欢迎吐槽。排序算法大一点分,有两类:基于比较的和不基于比较的。基于比较的算法都逃不了O(nlogn)的复杂度,也就是说不可能比这个复杂度还高了。因为每次比较至少得消耗logn的时间。不基于比较的排序因为省掉了比较,所以可以把复杂度提高到O(n),但几种非比较的排序算法应用都很受限,只有在特定的场合才能发挥出最优的性能。先说说几种基于比较的排序算法。Bubble Sort, Insertion Sort是两种复杂度为O(n^2)的稳定的排序算法。由于算法复杂度比较高,这两种算法似乎用的不是很多,但这两种算法也有自己的优点,一是这两种算法不需要额外的空间,二是当数列基本有序时,这两种算法的实际运行时间会有很大的提升空间,最优情况能到O(n)。Merge Sort和Binary Tree Sort是两种复杂度为O(nlogn)的稳定排序算法。这两种算法中,由于Binary Tree容易退化(AVL等操作可以尽量避免这种退化,但会增加复杂性),个人感觉Merge Sort似乎用的更多一些。他们都只需要O(n)的额外空间,所以对于大数据的排序是比较有利的。Selection Sort是O(n^2)的非稳定算法,不需要额外的空间。Selection Sort的复杂度和Bubble Sort一样(平均情况下,最好情况下Bubble Sort会到O(n)),但是Selection Sort所需要的交换操作次数比Bubble Sort少多了,所以平均情况下,虽然他们复杂度相同,但是Selection Sort要比Bubble Sort快。Shell Sort,Heap Sort,Quick Sort是三种复杂度为O(nlogn)的非稳定性排序算法,Shell Sort的平均复杂度其实应该是O(n^1.25)。这三种算法中,Quick Sort是需要O(logn)的辅助空间的(递归时候用),Heap Sort和Shell Sort不需要额外的辅助空间。平均情况下来说,Quick Sort是一种神器,确实是最快的,尽管在极端情况下它会退化到O(n^2)的复杂度,但是如果用随机化等方法优化,这种退化的可能行微乎其微,它确实应该是最快的!但是由于需要递归,需要额外的空间,所以对于百万级以上的数据,Heap Sort还是更有优势。然后是几种不基于比较的排序算法,他们都是线性的复杂度,而且都是稳定的排序算法。首先是Counting Sort,它需要O(n + k)的辅助空间。这是一种很简单的排序算法,实现起来也很容易,但受限于数据范围的分布,要求所有数据必须分布在一个较小的范围内(k)。Bucket Sort在k值较小的情况下,更像是Counting Sort的一种特殊情况,这时候它需要O(k)的辅助空间。它可以处理数据范围分布较为大的情况,但要求数据分布比较分散,最好是随机分布,数据越散越好,不然会降低性能,这种时候它需要O(n)的辅助空间(个人理解,不知道对不对。它需要定义m个桶,最终把n个元素全部丢到桶里,如果在桶内部采用就地排序算法,辅助空间就应该是O(n)了),在这种情况下,它的复杂度肯定是比较高的,因为要对桶内的元素排序,当然在桶内部排序时,由于桶内元素比较集中,因此可以配合Counting Sort,复杂度仍然会是线性的,但还会需要更多辅助空间,当然m值越大,算法性能就会越高,但这肯定会增加空间复杂度,这一点再次体现了时间性能与空间性能的矛盾性。Radix Sort更适用于多关键字的排序,它也受限于数据的特点。在多关键字排序的情况下,LSD比MSD有更好的性能,因为LSD不需要额外的空间。当然,应用LSD的时候要注意下次排序必须选用稳定的排序算法,不然会打乱低一级关键字的顺序。总结:排序算法有稳定的,也有不稳定,有基于比较的,也有不基于比较的,基于比较的算法相比之下,复杂度更高,但是应用范围较不基于比较的算法广。不基于比较的算法虽然可以达到线性复杂度,但都受限于数据特点。快排在大多数情况下,应该还是最快的算法,但即使是O(n^2)的算法,也应该引起足够的重视,因为他们在特定情况下会发挥出比快排更有的性能。另外,排序算法不一定非要用于排序,比如基数排序可以应用于后缀数组的倍增算法从而提高性能,小根堆可以应用于优先队列的实现等。


原创粉丝点击