面对现实,超越自己
逆水行舟,不进则退
posts - 269,comments - 32,trackbacks - 0
算法介绍
  计数排序是一个类似于桶排序的排序算法,其优势是对已知数量范围的数组进行排序。它创建一个长度为这个数据范围的数组C,C中每个元素记录要排序数组中对应记录的出现个数。这个算法于1954年由 Harold H. Seward 提出。     

      当输入的元素是 n 个 0 到 k 之间的整数时,它的运行时间是 Θ(n + k)。计数排序不是比较排序,排序的速度快于任何比较排序算法。

由于用来计数的数组C的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存。例如:计数排序是用来排序0到100之间的数字的最好的算法,但是它不适合按字母顺序排序人名。但是,计数排序可以用在基数排序中的算法来排序数据范围很大的数组。计数排序之所以能够突破前面所述的Ω(nlgn)极限,是因为它不是基于元素比较的。计数排序适合所需排序的数组元素取值范围不大的情况(范围太大的话辅助空间很大)。

定理:任意一个比较排序算法在最坏情况下,都需要做Ω(nlgn)次比较。


算法的步骤如下:

  • 找出待排序的数组中最大和最小的元素
  • 统计数组中每个值为i元素出现的次数,存入数组C的第i
  • 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
  • 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1

以下引自麻省理工学院算法导论——笔记:

Counting sort: No comparisons between elements.
• Input: A[1 . . n], where A[ j]􀂏{1, 2, …, k} .
• Output: B[1 . . n], sorted.
• Auxiliary storage: C[1 . . k] .

Counting sort
for i  ← 1 to k
do C[i]  ← 0
for j  ←1 to n
do C[A[ j]]  ← C[A[ j]] + 1   —> C[i] = |{key = i}|
for i  ← 2 to k
do C[i]  ← C[i] + C[i–1]        —>C[i] = |{key  ← i}|
for j  ← n downto 1
do B[C[A[ j]]]  ← A[ j]
C[A[ j]]  ← C[A[ j]] – 1

实例:


对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)



反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1






注:基于比较的排序算法的最佳平均时间复杂度为 O(nlogn)
     稳定性:算法是稳定的。


如果k小于nlogn可以用计数排序,如果k大于nlogn可以用归并排序。


代码实例:

 1 C++实现:
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 //n为数组元素个数,k是最大的那个元素
 6 void CountingSort(int *input, int size, int k){
 7 int i;
 8 int *result = new int[size]; //开辟一个保存结果的临时数组
 9 int *count = new int[k+1]; //开辟一个临时数组
10 for(i=0; i<=k; ++i)
11 count[i]=0;
12 //使count[i]等于等于i的元素的个数
13 for(i=0; i<size; ++i)
14 ++count[input[i]]; //count数组中坐标为元素input[i]的增加1,即该元素出现的次数加1
15 for(i=1; i<=k; ++i)
16 count[i] += count[i-1];
17 for(i=size-1; i>=0--i){ //正序来也行,但是到这来可以使排序是稳定的
18 --count[input[i]]; //因为数组下标从0开始,所以这个放在前面
19 result[count[input[i]]] = input[i]; //这个比较绕, count[input[i]-1] 就代表小于等于元素
    }  
20 copy(result,result+size,input); //调用copy函数把结果存回原数组
21 delete [] result; //记得释放空间
22 delete [] count;
23 }
24 int main()
25 {
26 int input[11]={2,7,4,9,8,5,7,8,2,0,7};
27 CountingSort(input,11,9);
28 for(int i=0; i<11++i)
29 printf("%d ",input[i]);
30 putchar('\n');
31 return 0;
32 }

 

posted on 2012-11-13 11:07 王海光 阅读(460) 评论(1)  编辑 收藏 引用 所属分类: 算法

FeedBack:
# re: 算法导论——计数排序(网易公开课)[未登录]
2012-11-14 09:24 | 春秋十二月
我对此略有研究,但有所变化和改进,详见http://www.cppblog.com/qinqing1984/archive/2012/05/31/176784.html  回复  更多评论
  

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理