Conclusions on Sorting Algorithm
================================

## 知识脉络总结

`快速排序`的思想是简单而深刻的，即`分而治之`的策略，需要注意它和`归并排序`在思想上的异同。`快速排序`的关键在于`partition`算法，本章给出了`partition`算法的三种实现，需要领会这三种不同的实现各自的特点是什么，是为了解决什么问题而出现的。需要指出的是，尽管在一般情况下`快速排序`运行的平均时间最短（这也是它被称作`快速排序`的原因)，可是在最坏情况下`快速排序`仍然需要`O(n^2)`的时间，可以通过改造`轴点`的选择算法，在一定程度上减小最坏情况出现的概率。在平均情况下，`快速排序`仅需要`O(nlogn)`的时间复杂度，要会证明这个结论。

`希尔排序`的正确性和有穷性不言而喻，其时间复杂度主要取决于`增量序列`的选择，例如`希尔序列`就是一个比较糟糕的序列，需要能够领会为什么`希尔序列`的性能较差。为了分析`希尔排序`的时间复杂度，首先需要理解`邮资问题`和`g-有序`的序列经过`h-排序`后仍然保持`g-有序`的证明，在此基础上，即可针对不同的`增量序列`给出复杂度的证明。

本章的剩余部分主要讨论算法层面的问题，集中讨论了`k选取问题`，`中位数选取`问题，`众数选取`问题以及`归并向量的中位数`定位问题。

对于`k选取问题`，可以基于`堆`结构给出若干算法，这些算法在`k`很大或者很小时都具有较为优化的性能(`O(n)`)，但是在`k = O(n)`时，算法的时间复杂度将退化为`O(nlogn)`。基于`快速排序`的思想，可以构造出`快速选择`(quickSelect)算法，它的平均时间复杂度为`O(n)`，证明方法和`快速排序`相仿，然而在最坏情况下，它的时间复杂度可以达到`O(n^2)`。最后教材上给出了一个最坏情况下仍然可以保持`O(n)`的`k选取`算法，它的基本思想是将整个序列划分成三个子序列，并且使得其中小于`轴点`的子序列（记作`L`）以及大于`轴点`的子序列（记作`G`）的规模都不小于`n / 4`，从而一次迭代后问题的规模至少可以缩减为原来的`3 / 4`；为此，需要合理选择`轴点`，具体的做法是首先将整个序列平均划分为若干很小的子序列，每个子序列的规模为`Q`，并且求出这些子序列的`中位数`，再递归地计算这些`中位数`组成的`中位数序列`的`中位数`，将结果作为`轴点`。`中位数选取`问题是`k选取`问题的一个特例，这里不再赘述。

对于`众数的选取`问题，关键在于明确`众数的定义`乃是序列中出现频数多于一半的元素，从而可以证明教材所给算法的正确性。

关于`归并向量的中位数`选择，首先可以采用蛮力策略，假想地对两个有序向量进行归并，该策略的时间复杂度为`O((m + n) / 2)`；若两个向量等长，则可以分别取两个向量的`中位数`以及`逆向中位数`进行比较，从而将问题的规模缩小一半；若允许向量不等长，可以对问题进行分类讨论：

+ 若两个向量的规模差距巨大，则可以对更长的向量进行'裁剪'，截除等长的两翼，从而问题归入到下一种情况。
+ 两个向量规模相当，则以较短的向量的中位数`mid1`为基础，分别构造出较长向量的前后两个中间数`mid2a, mid2b`，它们分别满足到向量的首尾的长度是`mid1`，通过将两者与`mid1`进行比较，从而可以截除接近一半的数据，问题的规模从而减少大约一半。这里不直接选择较长向量的中位数进行比较的原因，乃是需要保证两端截除的长度要相等，只有这样新问题的中位数才和原先的问题的中位数一致。
