《算法导论》第三版第8章 线性时间排序 练习&思考题 个人答案
8.1 排序算法的下界
8.1-1
解:n-1。
8.1-2
解:Θ(nlgn)\Theta(n\lg n)Θ(nlgn)。
8.1-3
证明:
n!2≤2n\frac{n!}{2} \le 2^n2n!≤2n
n!n≤2n\frac{n!}{n} \le 2^nnn!≤2n
n!2n≤2n⇔n!≤4n\frac{n!}{2^n} \le 2^n \Leftrightarrow n! \le 4^n2nn!≤2n⇔n!≤4n
对后两种,只能对较小的n存在。
8.1-4
证明:
(k!)n/k≤2h(k!)^{n/k} \le 2^h(k!)n/k≤2h
h≥lg(k!)n/k=(n/k)lg(k!)≥(n/k)(k/2)lg(k/2)(ex 8.1.2)=12nlgk−12n=Ω(nlgk)\begin{aligned}
h &\ge \lg(k!)^{n/k} \\
&= (n/k)\lg(k!) \\
&\ge (n/k)(k/2)\lg(k/2) & \text{(ex 8.1.2)}\\
&= \frac{1}{2}n\lg{k} - \frac{1}{2}n \\
&= \Omega(n\lg{k})
\end{aligned}h≥lg(k!)n/k=(n/k)lg(k!)≥(n/k)(k/2)lg(k/2)=21nlgk−21n=Ω(nlgk)(ex 8.1.2)
8.2 计数排序
8.2-1
解:中间过程略,最后B是{0, 0, 1, 1, 2, 2, 3, 3, 4, 6, 6},C是{0, 2, 4, 6, 8, 8, 9}
8.2-2
本题和8.2-3证明如下图。
8.2-3
证明如下图。
8.2-4
解:
COUNTING-INTERVAL(A, a, b) let C[0..k] be a new array count = 0 for i = 0 to k C[i] = 0 for j = 1 to A.length C[A[j]] = C[A[j]] + 1 for i = ceiling(a) to floor(b) count = count + C[i] return count
8.3 基数排序
8.3-1
略。。。
8.3-2
插入排序和归并排序是稳定的。对相等的元素记录其原下标,额外开销O(nlgn)O(n\lg n)O(nlgn)时间和O(n)空间。
8.3-3
8.3-4
可视为三位n进制数,进行特殊的基数排序。
8.3-5
解:d轮;10d10^d10d堆。
8.4 桶排序
8.4-1
略。。。
8.4-2
因为其中运用了插入排序作为子排序算法;可改为归并排序。
8.4-3
解:32\frac{3}{2}23;111
8.4-4
提示:将did_idi按照1:2:...:n1:\sqrt2:...:\sqrt n1:2:...:n划分为各桶。
8.4-5
思路:我觉得这题就是可以仿照8.4-4,找到一个桶的所有“划分分位”,将元素划分到各个桶间,然后就是类似于桶排序的步骤了。
思考题
8-1 (比较排序的概率下界)
a.
b.
c.
d.
e.
f.
8-2 (线性时间原址排序)
a.
解:计数排序。
b.
解:(仿)快速排序。
c.
解:插入排序。
d.
解:使用计数排序。
e.
解:同d;是稳定的。
8-3 (变长数据项的排序)
a.
思路:可以先对各元素的位数采用计数排序分成各“桶”,再在各“桶”内部采用基数排序。
b.
思路:在右侧补“0”直至与最长字符相齐。
8-4 (水壶)
a.
思路:依次对每一个红(蓝)壶,进行线性查找,找到与之大小相等的蓝(红)壶。
b.
证明思路:可用类似8.1节中的决策树进行证明。
c.
思路:随机找到一红壶→使用此红壶对蓝壶进行PARTITION→使用PARTITION返回的蓝壶(与红壶大小相等)对红壶进行PARTITION→在PARTITION后的前(后)部分中随机找到一红壶→使用此红壶对PARTITION后的前(后)部分蓝壶进行PARTITION→……
8-5 (平均排序)
a.
解:完全排序。
b.
解: 1,3,2,4,5,6,7,8,9,10。
c.
解:
“仅当”的证明:
∑j=ii+k−1A[j]k≤∑j=i+1i+kA[j]k⇕A[i]+∑j=i+1i+k−1A[j]k≤∑j=i+1i+k−1A[j]+A[i+k]k⇕A[i]k≤A[i+k]k⇕A[i]≤A[i+k]\frac{\sum_{j=i}^{i+k-1}A[j]}{k} \le \frac{\sum_{j=i + 1}^{i+k}A[j]}{k} \\
\Updownarrow \\
\frac{A[i] + \sum_{j=i+1}^{i+k-1}A[j]}{k} \le
\frac{\sum_{j=i+1}^{i+k-1}A[j] + A[i+k]}{k} \\
\Updownarrow \\
\frac{A[i]}{k} \le \frac{A[i+k]}{k} \\
\Updownarrow \\
A[i] \le A[i+k]k∑j=ii+k−1A[j]≤k∑j=i+1i+kA[j]⇕kA[i]+∑j=i+1i+k−1A[j]≤k∑j=i+1i+k−1A[j]+A[i+k]⇕kA[i]≤kA[i+k]⇕A[i]≤A[i+k]
反过来可证明“当”。
d.
思路:元素的下标对k取余可分为k组,每组有大概有n/k个数,对每组分别排序即可。
e.
证明思路:结合d与练习6.5-9可证明。
f.
证明思路:结合上面各题易证。
8-6(合并有序列表的下界)
a.
解:C2nnC_{2n}^nC2nn
b.
证明:
22nπn(1+O(1/n))≤l≤2h\frac{2^{2n}}{\sqrt{\pi n}}(1 + O(1/n)) \le l \le 2^hπn22n(1+O(1/n))≤l≤2h
h≥lg(22nπn(1+O(1/n)))=lg22n−lgπn+lg(1+O(1/n))=2n−o(n)\begin{aligned}
h & \ge \lg\bigg(\frac{2^{2n}}{\sqrt{\pi n}}(1 + O(1/n))\bigg) \\
& = \lg{2^{2n}} - \lg\sqrt{\pi n} + \lg(1 + O(1/n)) \\
& = 2n - o(n)
\end{aligned}h≥lg(πn22n(1+O(1/n)))=lg22n−lgπn+lg(1+O(1/n))=2n−o(n)
c.
证明:如果我们不比较两个连续的元素,我们不知道哪个元素首先出现。 与其他元素相比,它们完全无法区分。我们无法确定哪一个应该在前。(注意,如果它们在同一个序列中,我们不需要比较它们,因为我们已经有了这些信息)。
d.
如果元素的排序顺序是⟨a1,b1,a2,b2,…,an,bn⟩\langle a_1, b_1, a_2, b_2, \ldots,a_n, b_n \rangle⟨a1,b1,a2,b2,…,an,bn⟩,我们有两个序列⟨a1,a2,…,an⟩\langle a_1, a_2, \ldots,a_n \rangle⟨a1,a2,…,an⟩和⟨b1,b2,…,bn⟩\langle b_1, b_2, \ldots, b_n \rangle⟨b1,b2,…,bn⟩,那么需要比较2n-1对元素。 处理这种情况的任何算法必须在最坏的情况下执行2n-1比较。
8-7 (0-1排序引理和列排序)
(0-1排序引理部分)
a.
b.
(列排序部分)
注:这题我考虑了好久。。。题干中的条件“s必须是r的因子”和“r≥2s2r\geq2s^2r≥2s2”很重要,现在我把算法每一步结束后输出的结果分析一下。
(1) 在第1步后,输出结果:顶部一些全0行,底部一些全1行,中间有一些脏行。
注:脏行个数不限制,可能是0(假设输入的每一列都是由相等比例的0和1组成的),也可能是r(假设输入的一些列是全0,一些列是全1)
(2) 在第2步后,输出结果:{一些全0行→最多1个脏行→一些全1行}→{一些全0行→最多1个脏行→一些全1行}→……(一共s个{}内的内容)
注:第(2)步运用到了条件“s必须是r的因子”,这个条件使得每一列都能转化为整数行,没有哪一行是掺杂了转置前两列的元素。
(3) 在第3步后,输出结果:如d所述。
注:只要理解了第(2)步,这一步很容易理解,脏行最多有s个。
(4) 在第4步后,输出结果:如e所述,且脏列最多只有2个。
注:第3步后存在的最多s脏行,产生了s×s的脏区域。e中所说的“按列读取”其实就相当于在第3步后“按行读取”,肯定会有s2s^2s2个元素组成的脏区域。又因为条件“r≥2s2r\geq2s^2r≥2s2”,脏列肯定不会超过2个。
(5) 在第5步后,输出结果:对第4步中可能存在的脏列进行排序。
注:如果第4步后脏列只有1个,其实在此时排序已完成;如果第4步后脏列有2个,则2个脏列必然相邻,且每个脏列的脏区不会超过一列的一半(因为条件“r≥2s2r\geq2s^2r≥2s2”;且前一脏列的脏区在后半部分,后一脏列的脏区在前半部分)。
但需要注意的是,此时排序并不一定完成,因为虽然对每一脏列进行了排序,但如果有2个脏列的话,前一脏列的末尾处的1和后一脏列开始处的0,拼接后,显然还是不符合排序的原则的。
(6) 在第6步和第7步后,输出结果:此时按列读取的数组已经是排好序的数组了。
注:这两步其实就是对“第4步后脏列有2个”的情况进行处理,将前一脏列的后半部分与后一脏列的前半部分组合成一个新列(因为每个脏列的脏区不会超过一列的一半,所以实际上数组中剩下所有的脏区域都在此时集中到新列里),再进行排序,这样实际上数组的排序已经完成(因为按列读取的话,新列就是数组唯一的脏区域,它前面只有0,后面只有1)。
(7) 在第8步后,输出结果就是最终输出结果。
c.
由于偶数步骤盲目地执行,我们可以怀疑算法中有一些遗忘的元素。如果我们用一个不经意的比较交换算法执行奇数步骤,那么列排序显然是遗忘的,我们可以应用0-1排序引理。由于我们可以将这些步骤视为“黑盒子”,因此我们可以将排序算法替换为产生相同结果的任何其他算法(即任何排序算法),并且生成的列排序仍然会排序。
d.
d、e、f可由上面的分析得出。
e.
d、e、f可由上面的分析得出。
f.
d、e、f可由上面的分析得出。
g.
思路:因为没有了条件“s必须是r的因子”,所以每一列都无法转化为整数行,因此必然有一些行掺杂了转置前两列的元素。
解:
现在第2步的输出结果变为{一些全0行→最多1个脏行→一些全1行→一些脏行}→{一些全0行→最多1个脏行→一些全1行→一些脏行}→……(一共s-1个{}内的内容)→一些全0行→最多1个脏行→一些全1行。
在{}中,第一个脏行是之前列内部存在的,而第二个脏行是之前两列元素掺杂形成的,因此第一个脏行共有最多s个,第二个脏行共有最多s-1个(最差情况下,每相邻两列的元素都会掺杂)。因此最多有2s-1个脏行,而第3步不会增加新的脏行,所以第3步后中间最多2s-1行脏行。
4s2−2s4s^2-2s4s2−2s
h.
思路:两列元素掺杂形成脏区,必然是前一列的末尾是1,后一列的开始是0,改动后使得前后两列的衔接处元素相同即可。
解:奇数列升序排序,偶数列降序排序。这样可以使脏行数最多为s。
注:其实并不一定是衔接处的脏行被削除了,也有可能转置前前一列是全1,后一列是全0,这样转置后衔接处仍有脏行,但这样的话原列的内部必然没有脏区,所以列内部转置产生的脏行就没有了。
- 《算法导论》第三版第9章 中位数和顺序统计量 练习&思考题 个人答案
- 算法导论第8章线性时间排序答案
- 《算法导论》第三版第11章 散列表 练习&思考题 个人答案
- 《算法导论》第三版第31章 数论算法 练习&思考题 个人答案
- 《算法导论》第8章 线性时间排序 个人笔记
- 算法导论第八章线性时间排序课后答案
- 算法导论:第8章 线性时间排序__计数排序
- 算法导论 第8章 线性时间排序-计数排序的原址排序
- 《算法导论》第8章 线性时间排序 (1)计数排序
- 算法导论:第8章 线性时间排序__基数排序
- 《算法导论》第8章 线性时间排序 (1)计数排序
- 算法导论 第8章 线性时间排序 课后习题
- 《算法导论》第8章 线性时间排序 (1)计数排序
- 《算法导论》第8章 线性时间排序 (1)计数排序
- 算法导论学习笔记-第8章 线性时间排序
- 算法导论——lec 08 线性时间排序
- 【算法导论】第8章线性时间排序_计数排序、基数排序、桶排序
- 个人练习数据结构之--------------关于线性数据的有序数组以及之上的二分法查找、不同排序方法的学习
- 算法导论--线性时间排序
- 算法导论练习4.1-5:求出最大子数组的三种方法:暴力、归并、线性时间算法