计数排序(Counting Sort)Java

36 篇文章 0 订阅
11 篇文章 0 订阅

常见的排序算法,例如:冒泡,选择,快速等等。他们都是基于比较实现的排序算法。最快的快速排序算法的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)。而计数排序是一种特殊的排序算法,它的时间复杂度为 O ( 3 n + k ) O(3n+k) O(3n+k),在数据较多数据范围较小的情况下,计数排序比快速排序的效率更高。与此同时,计数排序是稳定的,相同的数据相对顺序保持不变。

示例:待排序数组array为[98, 97, 96, 98, 95, 100, 96, 98, 100, 99]。
算法步骤:
1、找到最小值min,最大值max,得到数据的极差1range = max - min + 1。
2、创建计数数组count,大小为range。
3、顺序遍历原数组,索引为i,数据element = array[i],映射到count数组中索引为index = element - min,将count[index]加1。表示数组中的元素element的个数加1。
4、顺序遍历count数组,索引为i,计算count[i] = count[i - 1] + count[i]。
5、逆序遍历原数组array,索引为i,数据element = array[i],映射到count数组中索引为index = element - min,将count[index]减1后的数据为j,然后将element保存到结果数组(res)中的索引为j的位置。

演示视频如下:

计数排序

由此可以看出:算法共有四次循环,其中三次遍历原数组,时间复杂度为 O ( n ) O(n) O(n),若数据范围为k,则遍历count数组的时间复杂度为 O ( k ) O(k) O(k),故总的时间复杂度为 O ( 3 n + k ) O(3n+k) O(3n+k)。不计算输出数组的情况下,空间复杂度为 O ( k ) O(k) O(k)
可以发现,数据范围对计数排序的复杂度影响较大。因此当数据范围非常大的时候不宜使用此算法。

Java代码实现如下:

/**
 * 计数排序
 * <p>创建日期:2020-06-05 11:56</p>
 *
 * @author PengHao
 */
public class CountSort {
    /**
     * <p>计数排序</p>
     * <p>时间复杂度为O(3n+k)</p>
     * <p>空间复杂度为O(k)</p>
     *
     * @param src 待排序数组
     * @return 排好序的数组
     */
    public static int[] countSort(int[] src) {
        // 数组中的最小值
        int min = src[0];
        // 数组中的最大值
        int max = src[0];
        for (int value : src) {
            if (value < min) {
                min = value;
            } else if (value > max) {
                max = value;
            }
        }

        // 数组中的数据范围
        int range = max - min + 1;
        // count[i]表示数组src中数据min + i的个数
        int[] count = new int[range];
        for (int value : src) {
            count[value - min]++;
        }

        // 累计,使得count[i]保存src中小于等于min + i的数据的个数
        for (int i = 1; i < range; i++) {
            count[i] += count[i - 1];
        }

        // 结果数组
        int[] res = new int[src.length];
        // 倒序遍历原数组,保持排序的稳定性
        for (int i = src.length - 1; i >= 0; i--) {
            // 获取数据在count数组中的索引
            int index = src[i] - min;
            // 个数减1
            count[index]--;
            // 数据src[i]排序后的索引是count[index]
            res[count[index]] = src[i];
        }
        return res;
    }
}

代码没有进行安全检查,所以待排序数组不能为空,并且至少有1个元素。


  1. 数学中极差的定义为:range = max - min。 ↩︎

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
排序计数排序是两种不同的排序算法。 桶排序的基本思想是将数组分到有限数量的桶里,再对每个桶中的元素进行排序,最后按照桶的顺序将元素依次列出来,形成有序序列。桶排序的时间复杂度取决于对每个非空桶进行排序时所选择的排序算法。当要排序的数据均匀分布时,桶排序可以达到线性时间复杂度。 计数排序是一种记录数据出现次数的排序算法。它的原理类似于桶排序,可以看作是一种特殊的桶排序算法计数排序遍历序列,并将每个元素放入对应的桶中。然后按照桶的顺序将元素依次放回原来的序列中。计数排序是一种稳定的排序算法,适用于数据范围较小的情况。 对于Java语言,你可以使用以下代码实现桶排序计数排序: 桶排序Java实现代码示例: ``` public void bucketSort(int[] arr, int bucketSize) { if (arr.length == 0) { return; } // 寻找数组的最大值和最小值 int min = arr[0], max = arr[0]; for (int i = 1; i < arr.length; i++) { if (arr[i] < min) { min = arr[i]; } else if (arr[i] > max) { max = arr[i]; } } // 桶的数量 int bucketCount = (max - min) / bucketSize + 1; List<List<Integer>> buckets = new ArrayList<>(); for (int i = 0; i < bucketCount; i++) { buckets.add(new ArrayList<>()); } // 将数组中的元素放入对应的桶中 for (int i = 0; i < arr.length; i++) { int bucketIndex = (arr[i] - min) / bucketSize; buckets.get(bucketIndex).add(arr[i]); } // 对每个桶中的元素进行排序,并放回原来的序列中 int index = 0; for (int i = 0; i < bucketCount; i++) { List<Integer> bucket = buckets.get(i); Collections.sort(bucket); for (int j = 0; j < bucket.size(); j++) { arr[index++] = bucket.get(j); } } } ``` 计数排序Java实现代码示例: ``` public void countingSort(int[] arr) { if (arr.length == 0) { return; } // 寻找数组的最大值和最小值 int min = arr[0], max = arr[0]; for (int i = 1; i < arr.length; i++) { if (arr[i] < min) { min = arr[i]; } else if (arr[i] > max) { max = arr[i]; } } // 计算数组中每个元素的出现次数 int[] counts = new int[max - min + 1]; for (int i = 0; i < arr.length; i++) { counts[arr[i] - min]++; } // 将计数数组中的元素依次放回原来的序列中 int index = 0; for (int i = 0; i < counts.length; i++) { while (counts[i] > 0) { arr[index++] = i + min; counts[i]--; } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值