计数算法

来源:互联网 发布:android三方数据库 编辑:程序博客网 时间:2024/06/05 22:58

转载于:http://blog.csdn.net/zy825316/article/details/19420349?reload

原理

核心思想:如果有10个人,给其年龄排序,当我们知道某一个人比另外5个人都大时,我们就知道他应该排在第6位。
直接看一次排序的完整过程,对下图中的A数据排序,注意该算法需要一个辅助数组,如下所示:
(图摘自Introduction to Algorithms,8.2Counting sort,P196)

我们可以看到数组A=[2,5,3,0,2,3,0,3]所带排序的数组,而数组C就是辅助数组,且按以下要求形成:
  • 数组C的长度是数组A的不重复的元素的个数
  • 用数组A的元素的值来做数组C的下标(所以要求带排序的数组只能是int型)
  • 数组C的元素的值是下标在数组A中出现的次数(数组C的第一个元素下标为0,代表数组A中值为a[4]和a[7]的元素,出现了两次,所以c[0]=2)

接着对数组C进行单独的一次操作,改变数组C的元素的值,使其的含义为:小于或者等于数组C下标的数的个数。(注意,数组C的下标的值就是数组A的元素的值),比如数组A中小于或者等于0的数只有0,两个;小于等于1的数只有0,还是两个;小于等于2的数有4个,两个0和两个2。以此类推。实际上,我们只用一句代码就完成了转换:C[j]=C[j]+C[j+1]

有了数组C的数据,我们就可以摆放正确的数组的位置了:比如对于元素5,我们知道比它小有7个(不包括等于它的那个),它理应在第8号位,前面7个留给小于它的数。那么还有等于的情况该怎么办呢? 我们采用这样的策略,倒着从数组A中取出元素,逐渐放置到数组B中,比如数组A的最后一个是3,比3小或者等于3的有7个,所以3应该放在第7号位。并且将c[3]减1。下图面几张图就是进行这个过程,数组C是已经减了之后的:



最后,我们将得到排好序的数组:

针对上述过程,写出伪代码:

  • 5行对应a图
  • 7/8行对应b
  • 10到12行对应c-e图
  • 执行完12行对应f图

特点

(摘自Introduction to Algorithms,8.2Counting sort,P196)

只能对int类型排序

很容易发现只能对int类型的数组排序,如果对float类型的数组排序,就使用不了辅助数组了。

时间复杂度

How much time does counting sort require? The for loop of lines 2–3 takes time O(k), the for loop of lines 4–5 takes time o(n), the for loop of lines 7–8 takes time O(k), and the for loop of lines 10–12 takes time O(n). Thus, the overall time is O(k+n). In practice, we usually use counting sort when we have k=O(n), in which case the running time is O(n).
其中:when we have k=O(n)我暂时没理解清楚,为什么时间复杂度等于一个k?

计数排序不是比较排序

  • 计数算法中没有出现比较
  • 排序算法的时间复杂度优于比较类排序
  • 比较类排序的时间复杂度不低于O(nlgn)

计数排序是稳定的

所谓稳定的:stable: numbers with the same value appear in the output array in the same order as they do in the input array. 
  • 我们有时会要求排序具有稳定性
  • radix sort(基数排序)需要利用计算排序,而且必须要求其稳定的

代码

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public class countingSort {  
  2.   
  3.     /** 
  4.      * @param args 
  5.      */  
  6.     public static void main(String[] args) {  
  7.         int a[]={2,5,3,0,2,3,0,3};  
  8.         int i;  
  9.         int[] b = countingsort(a);  
  10.         System.out.print("排序结果:");  
  11.         for(i=0;i<b.length;i++){  
  12.             System.out.print(b[i]+" ");  
  13.         }  
  14.               
  15.     }  
  16.         //传入一个全是int类型的数组,返回升序排序的数组  
  17.     private static int[] countingsort(int[] a) {  
  18.         int max=a[0];  
  19.         int min=a[0];  
  20.         for(int i=0;i<a.length;i++){//找出待排序的数组中最大和最小的元素  
  21.             if(a[i]>max){  
  22.                 max=a[i];  
  23.             }  
  24.             if(a[i]<min){  
  25.                 min=a[i];  
  26.             }  
  27.         }  
  28.         int c[]=new int[max-min+1];  
  29.         for(int i=0;i<c.length;i++){  
  30.             c[i]=0;  
  31.         }  
  32.         for(int i=0;i<a.length;i++){//统计数组中每个值为i的元素出现的次数,存入数组C的第i项  
  33.             c[a[i]]++;  
  34.         }  
  35.         for(int i=0;i<c.length;i++){//对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)  
  36.             if(i!=0){  
  37.                 c[i]=c[i]+c[i-1];     
  38.             }  
  39.         }  
  40.         int b[]=new int[a.length];  
  41.         int i;  
  42.         for(i=a.length-1;i>=0;i--){//反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1  
  43.             b[c[a[i]]-1]=a[i];  
  44.             --c[a[i]];  
  45.         }  
  46.         return b;  
  47.     }  
  48.   
  49. }  
0 0
原创粉丝点击