计数排序

来源:互联网 发布:银行程序员招聘要求 编辑:程序博客网 时间:2024/05/29 18:34

基本原理

计数排序的基本思想就是:加入输入一个数x,如果我们可以找到比x小的数有几个,那么就可以直接将x放入到对应的输出数组的位置。
比如输入一个数x=12,发现在输入的数据中,比12小的有4个,那么毫无疑问12就该排在第五位。
通过上述的描述,可能你会发现,诶那每次我要找到有几个数比12小,不都是要把数组遍历一遍吗?n个数的话就会需要O(n^2),不是慢到怀疑人生吗?

现在就来说一下怎么进行计数排序,首先需要三个数组:
输入数组A,输出数组B(就是保存将A进行排序后的数组),提供中间存储的数组C
现在假设输入数组A={2,5,3,0,2,3,0,3},其中最大的数为5,则令k=5;
那么数组C的大小就为K+1,全部初始化为0;

for i=0 to A.lengthC[A[i]]+=1;

上面这步的目的是统计在A的中每个数出现了几次,然后将这个数作为C数组的下标,出现的次数作为对应下标里面的值。
经过上面这步,C={2,0,2,3,0,1}

还记得在之前说的吗,计数排序是基于“计数排序的基本思想就是:加入输入一个数x,如果我们可以找到比x小的数有几个,那么就可以直接将x放入到对应的输出数组的位置。”,接下来这步就是来统计有几个数比X小。

for j=1;j<C.length;j++C[j]=C[j]+C[j-1]

经过这步C={2,2,4,7,7,8}
通过C数组我们就可以知道5应该排在第8位。这里你可能会对C数组产生疑问,别急,接下去看。

现在就是用到B数组的时候了

for j=A.length-1 to 0    C[A[j]]-=1;    B[C[A[j]]]=A[j];

B={0,0,2,2,3,3,3,5}

总的来说就是首先通过遍历一遍A数组,统计出A中每个数出现的次数得到C数组,然后通过C数组的C[i]=C[i]+C[i-1],可以知道每个数有几个数比自己小,也就是A中的每个数该排在哪个位置。这里出现重复的数,通过C[A[i]]-=1;自动处理了。

伪代码

来自《算法导论》
这里写图片描述

时间复杂度

从上面的伪代码看,第一个for循环时间复杂度是O(k),第二个是O(n),第三个是O(k),第四个是O(n),所以总的是O(k+n),特别当n==k的时候,时间复杂度是O(n)。

计数排序不需要比较操作,也不需要交换操作,是一种简单的排序方式,但是这是一种空间换时间的排序方式,类似的空间换时间的排序还有桶排序等。

特别的当O(k)>=O(nlogn)的时候,计数排序就不那么有效了。

java代码实现

public class CountingSort {    public static void main(String[] args) {           int[] A = {2,5,3,0,2,3,0,3};           int[] B = CountSort(A);           for(int i:B)               System.out.print(i+" ");    }    public static int[] CountSort(int[] A){        int[] B = new int[A.length];        int max=A[0], min=A[0];        for(int i:A){            if(i>max)                max=i;            if(i<min)                min=i;        }        int[] c =new int[max-min+1]; //对C数组的大小进行优化        for(int i:A){            c[A[i]-min]+=1;        }        for(int j=1;j<c.length;j++)            c[j]=c[j]+c[j-1];        for(int j=A.length-1;j>=0;j--){            c[A[j]-min]-=1;            B[c[A[j]-min]]=A[j];        }            return B;    }}

参考资料:
《算法导论》

原创粉丝点击