一、设有 k k k 个排好序的序列 s 1 , s 2 , ⋯ , s k s_1, s_2, \cdots, s_k s1,s2,⋯,sk,各个序列的长度已知,第 i i i 个序列长用 l i l_i li 表示。采用2路合并算法将这 k k k 个序列合并成一个有序的序列。假设采用的2路合并算法合并2个长度分别为 m , n m,n m,n 的序列需要 m + n − 1 m+n-1 m+n−1 次比较。
- 设计一个算法确定最佳的合并顺序,使得总共的比较次数最少。写出伪代码,并用文字简要描述算法。
- 证明你提出算法的正确性。
解:
-
采用贪心算法,要想使得总的比较次数最少,需要先合并短的序列,使得短序列合并最多次,使得长序列合并最少次。因此,我们每次选择长度最短的序列进行合并,并用队列存放各个序列的长度。
算法说明:构建霍夫曼树,叶子节点为 k k k 个序列长度,内结点为合并时需要比较的次数。用 k k k 存储数组中数据的个数,将数组进行从大到小排序。首先取出数组中最后两个数据即长度最短和次短的两个序列进行合并,并将合并后的序列长度存入数组中,此时将比较的总次数在序列长度之和的基础上减少 1 1 1 ,之后再对数组中的数据进行排序,重复上述操作,直到最终数组中只剩下一个数据为止。
- 算法实现代码:
int min(int l[],int k) { int min=0; BubbleSort(l, k); while(k>1){ int sum=l[k]; sum+=l[k-1]; k--; l[k]=sum; min+=sum-1; BubbleSort(l, k); } return min; } void BubbleSort(int l[], int k){ //从大到小 int temp; for (int j=0; j<k; j++){ for (int i=0; i<k-1-j; i++){ if (l[i] < l[i+1]){ temp=a[i]; a[i]=a[i+1]; a[i+1]=temp; } } } }
-
证明:【这里证明来自网络,事实上只要证明霍夫曼树的贪心选择性质和最优子结构性质就好了】
采用构造最大堆最小堆来证明,设有 n n n 个权值 W = { W 0 , W 1 , … , W n − 1 } W=\{W_0,W_1,…,W_{n-1}\} W={ W0,W1,…,Wn−1} 作为外结点的权值,构造两路合并树的贪心算法将生成一棵具