变长数据项的排序
  a. 给定一个整数数组,其中不同的整数所包含的数字的位数可能不同,但该数组中,所有整数中包含的总数字位数为nn。设计一个算法,使其可以在O(n)O(n)时间内对该数组进行排序。
  b. 给定一个字符串数组,其中不同的字符串所包含的字符数可能不同,但所有字符串中的总字符个数为nn。设计一个算法,使其可以在O(n)O(n)时间内对该数组进行排序。(注意:此处的顺度是指标准的字典序,例如a<ab<ba < ab < b。)
  
  
  a.
  假设数组一共有mm个元素,各元素的位数分别为d1,d2,,dmd_1, d_2, …, d_m,显然有i=1mdi=n\sum_{i=1}^m{d_i} =n。如果采用基数排序,运行时间为O(dmaxm)O(d_{max}m),其中dmax=max1imdid_{max}=\max_{1≤i≤m}{d_i},这与题目要求的O(n)O(n)运行时间不符。例如,假设元素个数m=n/2+1m = n/2 + 1,有一个元素的位数为n/2n/2,其他n/2n/2个元素的位数都为11,这种情况下基数排序的运行时间为O(n2)O(n^2)
  为了可以在O(n)O(n)时间内完成排序,考虑先按照元素的位数对元素进行分组,相同位数的元素分为一组,然后采用基数排序分别对每组元素进行排序,然后按照位数从小到大依次输出每组元素即可完成排序。
  算法导论 — 思考题8-3 变长数据项的排序
  该算法的时间复杂度取决于两部分,一部分是分组的时间,一部分是对各组元素进行排序的时间。分组的时间取决于确定各元素的位数所花费的时间,对于一个有did_i位的元素,需要Θ(di)Θ(d_i)时间来确定它的位数。于是,确定所有元素的位数所花费的总时间为i=1mΘ(di)=Θ(n)\sum_{i=1}^m{Θ(d_i)}=Θ(n)。对各组元素的排序采用基数排序。对于第jj组来说,假设其中有mjm_j个元素,该组元素都包含jj个数位,基数排序的时间为Θ(jmj)Θ(j•m_j)。于是,对各组元素进行基数排序的总时间为j=1nΘ(jmj)=Θ(n)\sum_{j=1}^n{Θ(j∙m_j)}=Θ(n)。根据以上分析,该算法的时间复杂度为Θ(n)Θ(n)
  
  b.
  同样考虑借用基数排序的思想。在对数字的基数排序中,排序从低位开始,再到高位。与此不同,在对字符串的基数排序中,排序先从最左边的字符开始,再到右边的字符。下面给出一个例子。
  算法导论 — 思考题8-3 变长数据项的排序
  注意,第一轮排序对所有字符串的最左边的字符进行排序。在第一轮排序过后,所有字符串按照最左边的字符进行分组(如上图所示,第一轮排序过后,at和a为一组,box和bat为一组,fix、fox和fit为一组,I为一组)。因为要求按字典序来排序,所以可以断言,在最终排好序的序列中,第一组字符串肯定排在第二组字符串之前,第二组字符串也肯定排在第三组字符串之前……。于是在第二轮排序中,分别对第一轮分组后的各组元素进行组内排序,而不改变组与组之间的顺序。第二轮排序之后,又可以按各字符串的第二个字符进行分组,第三轮排序又针对第二轮的分组进行组内排序,如此递归下去,最后可以完成整个字符串序列的排序。
  假如所有字符串都是C风格字符串(即字符串以’\0’结尾),假设第ii个字符串的长度为lil_i,那么在第li+1l_i+1轮排序中,该字符串以’\0’参与排序,它一定会排在所在分组的前列,因为字符’\0’的值小于其他任何字符的值,而所有长度大于lil_i的字符串都排在这个长度为lil_i字符串的后面,这符合字典序。所以在第li+2l_i+2轮排序中,这个长度为lil_i字符串字符串可以不用参与排序,只需要让所有长度大于lil_i的字符串参与排序。
  根据以上分析,一个长度为lil_i的字符串会参与li+1l_i+1轮排序。如果每一轮排序都采用线性时间的计数排序,那么一个长度为lil_i的字符串在每一轮排序中贡献O(1)O(1)时间,在所有li+1l_i+1轮排序中贡献O(li+1)O(l_i+1)时间。于是,对所有字符串进行排序的总时间为
  i=1mO(li+1)=O(i=1m(li+1))=O(n+m)=O(n)\sum\limits_{i=1}^m{O(l_i+1)} =O(\sum\limits_{i=1}^m{(l_i+1)})=O(n+m)=O(n)
  在上式中,mm为字符串的个数。假如没有空字符串,即所有字符串的长度至少为11,则肯定有mnm ≤ n,所以在上式中O(n+m)=O(n)O(n+m) = O(n)是成立的。
  下面组出该算法的伪代码。
  算法导论 — 思考题8-3 变长数据项的排序
  要对整个字符串数组AA进行排序,只需要调用SORTSTRING(A,1,A.length,1){\rm SORT-STRING}(A, 1, A.length, 1)即可。

代码链接
  https://github.com/yangtzhou2012/Introduction_to_Algorithms_3rd/tree/master/Chapter08/Problem_8-3

相关文章: