算法导论第8章习题
Notes
- 前面的排序都是基于比较排序,有时候不需要比较也可以排序。关键是那些东西有一个好的表示,比如说整数。
- 用decision tree证明,\(\Omega(n \lg n)\)是所有比较排序算法的下界。
- 决策树中间节点表示比较的两个东西,叶子节点表示元素的一个置换,决策树的每条边表示这个算法在这个节点获得的比较信息。每个置换至少出现一次,叶子的数目是n!个。
- 不同算法有不同的决策树。比如最笨的最小值排序。它最短的path是这样的:1跟2~n比较的node –> 2跟3~n比较的node –> 。。。。而快排最短的path是,pivot和其他全部比较的n-1个node –> 中间某个pivot和(n-1)/2个元素比较得到的node –> 。。。。
- 算法执行的比较次数与决策树的路是对应的。所以说,插入排序的最长path的长度是\(\Theta(n^2)\),归并排序merge sort的是\(\Theta(n \lg n)\)。这样我们可以不去分许算法真实是怎么运行的,而是通过分析决策树的路就可以了。换个角度更清楚。
- 引理说树的高度\(l \le 2^h\)。因为至少有n!个叶子,一化简h就至少有\(\Omega(n \lg n)\)。
- 线性排序方法
- 计数排序 Counting sort
- 计数排序有假设要求所有元素最大值k要合适.排序[0,2,5,6]可以,排序[0,2^10,2^1024]那就死翘了。因为中间的辅助数组有k个大小,你说这不浪费嘛。而且时间复杂度是O(n+k)。一般是n大。但是k大的话就得不偿失了。
- 算法流程:1. 把元素A[i]装到相应的C[A[i]]中。2.把C[i]作为每个元素i的计数变成小于等于i的累积计数。3. 这时候表示C[i]表示i元素的在数组第几个位置。j从n递减到1,B[C[A[ j ]]] =A[ j ]。B有A的大小。C[A[ j ]] ← C[A[ j ]] − 1,自减1。
- k要小,最好小于8bit,也就是小于256。
- 基数排序 Radix sort
- key:先排序最低位的数字。否则要维护d个中间数组。stable也很重要。
- 算法流程:从低到高依次对数字位用stable的排序。
- \如果用计数排序作为中间排序方法:O(d(n+k))
- 有时候不一定非得按照10进制个十百千万顺序排序。可以对bits分组,r个一组r个一组,共b/r组。\( \Theta(\frac{b}{r}(n+2^r))。如果r约等于\(\lg n\)那么有\(\Theta(bn/\lg n)\)。r太小,就比前面那个复杂度稍大。r太大,那就是n^2复杂度。
- 比如2^16次32bits的整数,r取16bits,只要跑两趟就OK了。
- 桶排序 Bucket sort
- 假设:数字的输入是均匀分布在[0,1),这个假设在习题中得到放松。
- 把[0,1)区间划分成等大小的n个bucket。你看bucket大小的随着n变化,这算法肯定很给力。习题给出不必用大小相等的桶来适应分布不均匀的数据。每个桶用分别排序,然后把桶里的数据都串起来。
- 一旦一个桶里很多元素,那就悲剧了。每个桶期望有1个元素。那么一个桶排序期望时间\(O(1)\)。详细的分析由E(T(n))归结到求一个桶里的数量的平方的期望E[X_ij^2]
- 注意这是概率分析,要根据输入数据的概率分布。如果是随机算法,我们是强加一个概率分布到输入数据上,不一定要均匀分布。
- 计数排序 Counting sort
Exercises
8.1-1 n,发生在A1<=A2<=A3<= …
8.1-2 假设n是偶数even。把连加号拆成两项\[ \sum_{i=1}^{n} \lg (i) = \sum_{i=1}^{n/2} \lg (i) + \sum_{i=n/2+1}^{n} \lg (i) \]
上界:\[\sum_{i=1}^{n/2} \lg (i) + \sum_{i=n/2+1}^{n} \lg (i) \le \frac{n}{2}\lg(\frac{n}{2}) + \frac{n}{2} \lg(n) = n \lg(n) – \frac{n}{2}\]
下界:\[\sum_{i=1}^{n/2} \lg (i) + \sum_{i=n/2+1}^{n} \lg (i) \ge \frac{n}{2}\lg2 + \frac{n}{2}\lg(\frac{n}{2}) = \frac{n}{2}\lg (n) \]
8.1-3 只要考察以这些点作为叶子的二叉树的高度就可以了。当#leaf=n!/2时候:\(h \ge \lg n \ge lg(\frac{n!}{2} \ge \frac{n}{2}\lg(n) – 1 ) \)。树的高度超过了\(\Theta(n)\),所以木有这样的比较排序算法。剩下的两个也是不可能的。
8.1-4 \( k!^{\frac{n}{k}} \le 2^h \Rightarrow k=\Omega(n\lg k)\)
8.2-1 略
8.2-2 Counting sort is stable。因为如果A[i]=A[j],i<j,因为j是递减的所,所以A[j]先得到C数组中记录的position,而A[i]则经过Line11C数组的递减后,得到的position自然要小一点。在B的位置要比A[i]靠前。
8.2-3 同上
8.2-4 同Counting sort的Line1到Line8,最后只要输出C[b]-C[a-1]
8.3-1 略
8.3-2 稳定的算法:插入,合并。不稳定的:堆排序,快排。这个方法很巧。先给每个元素编号index。先比较两个元素本身,如果还是相等的话,再比较index。空间复杂度需要额外的\(\Omega(n\lg n)\)空间。因为每个index可以\(\lg n\)大小的数字来表示,这样有n个。时间复杂度只是增加了常数项。
8.3-3