排序-计数排序

计数排序

简介

计数排序(Counting sort)是一种线性时间的排序算法。

工作原理

计数排序的工作原理是使用一个额外的数组 C C C,其中第 i i i 个元素是待排序数组 A A A 中值等于 i i i 的元素的个数,然后根据数组 C C C 来将 A A A 中的元素排到正确的位置。

它的工作过程分为三个步骤:

  1. 计算每个数出现了几次;
  2. 求出每个数出现次数的 前缀和;
  3. 利用出现次数的前缀和,从右至左计算每个数的排名。

性质

稳定性

计数排序是一种稳定的排序算法。

时间复杂度

计数排序的时间复杂度为 O ( n + w ) O(n+w) O(n+w),其中 w w w 代表待排序数据的值域大小。

代码实现

计数排序

    public static void countingSort(int[] arr) {
        // 判空及防止数组越界
        if (arr == null || arr.length <= 1) {
            return;
        }
        // 找到最大值,最小值
        int max = arr[0];
        int min = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i];
            } else if (arr[i] < min) {
                min = arr[i];
            }
        }
        // 确定计数范围
        int range = max - min + 1;
        // 建立长度为 range 的数组,下标 0~range-1 对应数字 min~max
        int[] counting = new int[range];
        // 遍历 arr 中的每个元素
        for (int element : arr) {
            // 将每个整数出现的次数统计到计数数组中对应下标的位置,这里需要将每个元素减去 min,才能映射到 0~range-1 范围内
            counting[element - min]++;
        }
        // 记录前面比自己小的数字的总数
        int preCounts = 0;
        for (int i = 0; i < range; i++) {
            // 当前的数字比下一个数字小,累计到 preCounts 中
            preCounts += counting[i];
            // 将 counting 计算成当前数字在结果中的起始下标位置。位置 = 前面比自己小的数字的总数。
            counting[i] = preCounts - counting[i];
        }
        int[] result = new int[arr.length];
        for (int element : arr) {
            // counting[element - min] 表示此元素在结果数组中的下标
            result[counting[element - min]] = element;
            // 更新 counting[element - min],指向此元素的下一个下标
            counting[element - min]++;
        }
        // 将结果赋值回 arr
        for (int i = 0; i < arr.length; i++) {
            arr[i] = result[i];
        }
    }

倒序遍历的计数排序

    public static void countingSort(int[] arr) {
        // 防止数组越界
        if (arr == null || arr.length <= 1) {
            return;
        }
        // 找到最大值,最小值
        int max = arr[0];
        int min = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i];
            } else if (arr[i] < min) {
                min = arr[i];
            }
        }
        // 确定计数范围
        int range = max - min + 1;
        // 建立长度为 range 的数组,下标 0~range-1 对应数字 min~max
        int[] counting = new int[range];
        // 遍历 arr 中的每个元素
        for (int element : arr) {
            // 将每个整数出现的次数统计到计数数组中对应下标的位置,这里需要将每个元素减去 min,才能映射到 0~range-1 范围内
            counting[element - min]++;
        }
        // 每个元素在结果数组中的最后一个下标位置 = 前面比自己小的数字的总数 + 自己的数量 - 1。我们将 counting[0] 先减去 1,后续 counting 直接累加即可
        counting[0]--;
        for (int i = 1; i < range; i++) {
            // 将 counting 计算成当前数字在结果中的最后一个下标位置。位置 = 前面比自己小的数字的总数 + 自己的数量 - 1
            // 由于 counting[0] 已经减了 1,所以后续的减 1 可以省略。
            counting[i] += counting[i - 1];
        }
        int[] result = new int[arr.length];
        // 从后往前遍历数组,通过 counting 中记录的下标位置,将 arr 中的元素放到 result 数组中
        for (int i = arr.length - 1; i >= 0; i--) {
            // counting[arr[i] - min] 表示此元素在结果数组中的下标
            result[counting[arr[i] - min]] = arr[i];
            // 更新 counting[arr[i] - min],指向此元素的前一个下标
            counting[arr[i] - min]--;
        }
        // 将结果赋值回 arr
        for (int i = 0; i < arr.length; i++) {
            arr[i] = result[i];
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值