计数排序 小解

     前天看了《计算机编程艺术 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的时间)的情况下,在原数组中做到存放排好序的结果,具体做法请见代码。

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

你可能感兴趣的:(排序)