线性时间排序

线性时间排序

  • 前言
  • 计数排序
  • 基数排序
  • 桶排序
  • 总结

前言

  之前提到的排序算法有归并排序、堆排序、快速排序、插入排序,这些排序都是基于比较的,因此称这类排序为比较排序。比较排序的下界为 Ω ( n l g n ) \Omega(nlgn) Ω(nlgn),其中快速排序、堆排序、归并排序都可以达到这个时间性能。在本篇博客,将介绍几个线性时间排序算法,线性时间排序算法指的是排序 n n n个元素使用的时间为 Θ ( n ) \Theta(n) Θ(n)

计数排序

  计数排序的伪代码如下:
COUNTING-SORT(A,B,k)

let C[0..k] be a new array
for i=0 to k
	C[i]=0
for j=1 to A.length
	C[A[j]]=C[A[j]]+1
// 此时C[i]中为待排序列A中数字i的数量
for i=1 to k
	C[i]=C[i]+C[i-1]
//此时C[i]中为A中小于i或等于数字i的数量
for j=A.length downto 1
	B[C[A[j]]]=A[j]
	C[A[j]]=C[A[j]]-1

  上述方法实现的功能是排序A,并将排序好的序列输出到B,其中传入参数k为A中的数字范围,以序列 A = [ 2 , 5 , 3 , 0 , 2 , 3 , 0 , 3 ] A=[2,5,3,0,2,3,0,3] A=[2,5,3,0,2,3,0,3]为例, A A A中的数值范围为0~5,因此k为5,具体排序步骤如下:
线性时间排序_第1张图片
  图(a)中是执行完第二个for循环之后的C中的值,其中C[0]=2代表A中为0的数字有两个,其余的依次类推;图(b)中是执行完第三个for循环之后C中的值,其中C[0]=2代表A中小于0或等于0的数字有2个,C[2]=4代表A中小于2或等于2的数字有4个,其余的依次类推。
  图(c)是第四个for循环执行完一轮之后B跟C的状态,这个for循环的作用是将原序列 A = [ 2 , 5 , 3 , 0 , 2 , 3 , 0 , 3 ] A=[2,5,3,0,2,3,0,3] A=[2,5,3,0,2,3,0,3]从最后一个元素有序的放到B中。这里仅仅说明了代码的作用,并没有说明具体怎么实现的,伪代码的实现认真看伪代码和例子与配图就很容易理解了。
  分析伪代码可知,第一个跟第三个for循环花费的时间为 O ( k ) O(k) O(k),第二个跟第四个for循环花费的时间为 O ( n ) O(n) O(n);因此计数排序花费的时间为 O ( n + k ) O(n+k) O(n+k),其中k为排序数列中数字的范围,n为排序数列中数字的个数。
  当 k < n kk<n时,使用计数排序的时间为 O ( n ) O(n) O(n);当 k > n k>n k>n时计数排序的时间为 O ( k ) O(k) O(k);除此之外,计数排序是稳定的,即具有相同值得元素在输出数组中的相对次序与它们在输入数组中的相对次序相同。

基数排序

  基数排序看起来比较简单,比如有n个b位数,从小到大分别排序每一位,就完成排序了如下所示,先排序个位数,再排序十位数,最后排序百位数。
线性时间排序_第2张图片
  若排序每一位数采用的是计数排序的话,每一轮计数排序花费时间为 O ( n + k ) O(n+k) O(n+k),总共b轮,因此总共花费时间为 O ( b ( n + k ) ) O(b(n+k)) O(b(n+k))
  因此在每一轮采用技术排序,且 n > k n>k n>k,b为常数的情况下,基数排序的时间为 O ( n ) O(n) O(n)

桶排序

  桶排序是计数排序的直接升级版,只不过将计数排序中的C的每一位数变成一个“桶“,桶里放着一个范围的数,先排序每个桶里的数然后在将桶串起来,桶排序的期望运行时间 O ( n ) O(n) O(n)

总结

  本篇博客介绍了几种线性时间排序,其中基数排序跟桶排序都是基于计数排序的,桶排序花费的时间的具体证明比较麻烦,这里未进行详细描述。

你可能感兴趣的:(算法导论)