计数排序

基本思想: 对每一个输入元素x,确定出小于x的元素个数。有了这一信息,就可以把x直接放到它在最终输出数组中的位置上。例如,如果有17个元素小于x,则x就属于第18个输出位置。

计数排序是一个非基于比较的排序算法。它的优势在于在对一定范围内的整数排序时,它的复杂度为Ο(n+k)(其中k是整数的范围),快于任何比较排序算法。当然这是一种牺牲空间换取时间的做法,而且当O(k)>O*(n*log(n))的时候其效率反而不如基于比较的排序(基于比较的排序的时间复杂度在理论上的下限是*O(n*log(n)), 如归并排序,堆排序),计数排序是稳定的。

算法过程: 假设输入的线性表L的长度为n,L=L1,L2,..,Ln;线性表的元素属于有限偏序集S,|S|=k且k=O(n),S={S1,S2,..Sk};则计数排序可以描述如下:
1、扫描整个集合S,对每一个Si∈S,找到在线性表L中小于等于Si的元素的个数T(Si);
2、扫描整个线性表L,对L中的每一个元素Li,将Li放在输出线性表的第T(Li)个位置上,并将T(Li)减1。

给定数组a[8]={2,5,3,0,2,3,0,3};
这里写图片描述

Java代码:

public class LinearTimeSorter {

    /**
     * 计数排序,所有的元素都在0和max之间。
     */
    public static void countingSort(int[] array, int fromIndex, int toIndex, int max) {
        int[] counting = new int[max + 1];
        for (int i = fromIndex; i < toIndex; i++) {
            counting[array[i]]++;
        } // counting[i]现在包含值为i的个数

        for (int i = 1; i < counting.length; i++) {
            counting[i] += counting[i-1]; 
        } // counting[i]现在包含值小于等于i的个数

        int[] tempArray = new int[toIndex - fromIndex];
        for (int i = toIndex - 1; i >= 0; i--) { // 注意:这里是反向遍历,只有这样才是稳定的
            tempArray[--counting[array[i]]] = array[i];
        }

        // copy back
        System.arraycopy(tempArray, 0, array, fromIndex, tempArray.length);
    }

    public static void countingSort(int[] array, int max) {
        countingSort(array, 0, array.length, max);
    }

    /**
     * 计数排序,所有的元素都在min和max之间。
     */
    public static void countingSortMinMax(int[] array, int fromIndex, int toIndex, int min, int max) {
        int[] counting = new int[max - min + 1];
        for (int i = fromIndex; i < toIndex; i++) {
            counting[array[i]-min]++;
        } // counting[i]现在包含值为(i+min)的个数

        for (int i = 1; i < counting.length; i++) {
            counting[i] += counting[i-1]; 
        } // counting[i]现在包含值小于等于(i+min)的个数


        int[] tempArray = new int[toIndex - fromIndex];
        for (int i = toIndex - 1; i >= 0; i--) {
            tempArray[--counting[array[i] - min]] = array[i];
        }

        // copy back
        System.arraycopy(tempArray, 0, array, fromIndex, tempArray.length);
    }

    public static void countingSortMinMax(int[] array, int min, int max) {
        countingSortMinMax(array, 0, array.length, min, max);
    }

    /**
     * 计数排序,自动决定min和max。
     */
    public static void countingSort(int[] array) {
        if (array.length <= 1) return;
        int min = array[0];
        int max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (min > array[i]) min = array[i];
            if (max < array[i]) max = array[i];
        }
        countingSortMinMax(array, min, max);
    }
    public static void main(String[] args) {
        int[] a = new int[] {2, 5, 3, 0, 2, 3, 0, 3};
        countingSort(a, 5);
        System.out.println(Arrays.toString(a));

        a = new int[] {0, 3, 1, -2, 0, 1, -2, 1};
        countingSortMinMax(a, -2, 3);
        System.out.println(Arrays.toString(a));
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值