计数排序 小解

     前天看了《计算机编程艺术 vol3》的计数排序,以前的理解只是表面上的而且是模糊的。计数排序,原理很简单,顾名思义:就是通过记录每个数在数组中有多少其他的数比这个数小(即这个数在数组中排序后的位置)。好吧,废话少说,先上代码吧。

代码
1 #include<stdio.h>
2 #include<stdlib.h>
3
4  //计数排序原理:记录每一个元素在最后排序后的数组中的位置(也就是比多少个元素大)
5  //时间复杂度O(n*n)
6  
7
8 void count_sort(int * array,size_t size)
9 {
10 unsigned int* counters = malloc(size*sizeof(unsigned int));
11 int i;
12 for(i=0;i<size;i++)
13 counters[i]=0;
14 int j;
15 //填入每个元素的位置
16 for(i=0;i<size;i++)
17 {
18 int now = array[i];//参照数
19 for(j=i+1;j<size;j++)
20 {
21 int at = array[j];//待比较数,之所以要从i+1开始,是为了避免重复
22 if(now > at)
23 {
24 counters[i]++;//如果大于(不包括=是因为考虑到排序稳定性)
25 }
26 else
27 {
28 counters[j]++;//小于等于
29 }
30 }
31 }
32 //现在要把array中的元素排序
33 for(i=0;i<size;i++)
34 {
35 unsigned int at = counters[i];//at为下一个要放入该放入的位置
36 int at_array = i;//现在要处理的数组元素位置
37 if(at!=-1)
38 {
39 int value = array[i];//要放入的值
40 while(at!=-1)
41 {
42 int tmp = array[at];
43 array[at]= value;
44 counters[at_array]=-1;
45 at_array = at;
46 at = counters[at];
47 value = tmp;
48 }
49 }
50 }
51 free(counters);
52 }
53
54 int main()
55 {
56 int n;
57 scanf("%d",&n);
58 int* array = (int*)malloc(n*sizeof(int));
59 int i;
60 for(i=0;i<n;i++)
61 {
62 scanf("%d",&array[i]);
63 }
64 count_sort(array,n);
65 printf("After sort:");
66 for(i=0;i<n;i++)
67 {
68 printf("%d ",array[i]);
69 }
70 printf("\n");
71 free(array);
72 return 0;
73 }
74
75

    要讨论的问题有三个:

      1.时空复杂性,时间复杂性很简单,两重循环是O(n*n),空间需要额外的n的空间来存储每个元素的计数。(在本算法中少用了n的空间,也算是优化 吧,这点在第3点详细说明)。

      2.排序的稳定性问题,乍看上去排序貌似没有考虑相等的问题,但是在28行考虑到了在后面相等的元素,使其排位后移。所以该排序是稳定的。

      3.结果存放问题,通常的解法是申请一个相同大小的空间按照计数数组(程序中的counters)填入,然后再覆盖原数组内容。这样会需要额外的n的空间。本程序中在不改变时间复杂度(结果存放都用了n的时间)的情况下,在原数组中做到存放排好序的结果,具体做法请见代码。

在下一篇博文中,我将介绍计数排序的一个变种——统计计数排序,它在某些场合下表现的相当的出色呢啊。嘿嘿,先卖个关子哦。

posted on 2010-11-27 21:02  Weifeng Wang  阅读(279)  评论(0编辑  收藏  举报

导航