排序优化——如何实现一个通用的、高性能的排序函数
几乎全部的编程语言都会提供排序函数,好比 C 语言的 qsort(), C++ STL 中的 sort(),这些排序函数是如何实现的呢?
1. 如何选择合适的排序算法?
若是要实现一个通用的高效率的排序函数,咱们应该选择那种排序算法呢?

- 线性排序算法的时间复杂度比较低,适用场景特殊,所以不适合做为通用的排序函数。
- 小规模数据能够选择时间复杂度为 $O(n^2)$ 的算法,大规模数据选择时间复杂度为 $O(nlogn)$ 的算法则会更加高效。为了兼顾任意规模的数据,通常会首选复杂度为 $O(nlogn)$ 的算法来实现排序函数。
- 归并排序虽然最好状况、最坏状况和平均状况下时间复杂度均可以作到 $O(nlogn)$,但它不是原地排序算法,空间复杂度为 $O(n)$,排序的时候须要的额外空间和源数据通常大,空间消耗太高。
2. 如何优化快速排序?
快速排序最坏状况下时间复杂度退化为 $O(n^2)$ ,咱们怎样来避免这种状况的发生呢?
- 实际上,这种 $O(n^2)$ 复杂度出现的主要缘由仍是分区点选取得不合理。
- 理想的分区点应该是,被分区点分开的两个区间,数据的数量差很少。
2.1. 分区点优化问题
- 三数取中法。从待排序数据首、尾、中分别取出一个数,而后对比大小,以这三个数的中间值做为分区点。
- 若是排序数据比较多,可能要“五数取中”或者“十数取中”。
- 随机法。每次从要排序的区间随机选择一个元素做为分区点,这种状况下,就能够避免每次分区点都选得很是糟糕。
2.2. 堆栈溢出问题
快速排序是利用递归来实现的,当递归的的深度过深时,就会致使堆栈溢出。
- 限制递归深度。当递归次数超过咱们设定的阈值时,就中止递归。
- 在堆上模拟函数调用栈。手动模拟递归压栈出栈过程,解除系统栈大小的限制。
3. C 语言的 qsort() 函数?
- qsort 优先使用归并排序,在数据规模比较小的时候,以空间换时间。
- 当数据规模比较大时,qsort 会改成快速排序,以三数取中法来选取分区点。
- qsort 经过在堆上模拟函数调用栈来解决堆栈溢出问题。
- 当快速排序区间内元素小于等于 4 时,qsort 退化为插入排序。由于在小数据规模下, $O(n^2)$ 时间复杂度算法并不必定比 $O(nlogn)$ 的算法执行时间长。
参考资料-极客时间专栏《数据结构与算法之美》算法
获取更多精彩,请关注「seniusen」!
编程
欢迎关注本站公众号,获取更多信息