排序算法之计数排序

目录


一、简介

算法 平均时间复杂度 最好时间复杂度 最坏时间复杂度 空间复杂度 排序方式 稳定性
计数排序 O(n+k ) O(n+k) O(n+k) O(k) Out-place 稳定

稳定:如果A原本在B前面,而A=B,排序之后A仍然在B的前面;

不稳定:如果A原本在B的前面,而A=B,排序之后A可能会出现在B的后面;

时间复杂度: 描述一个算法执行所耗费的时间;

空间复杂度:描述一个算法执行所需内存的大小;

n:数据规模;

k:"桶"的个数;

In-place:占用常数内存,不占用额外内存;

Out-place:占用额外内存。

计数排序,又叫非比较排序。顾名思义,该算法不是通过比较数据的大小来进行排序的,而是通过统计数组中相同元素出现的次数,然后通过统计的结果将序列回收到原来的序列中。

核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。

算法步驟:

(1)找出待排序的数组中最大和最小的元素

(2)统计数组中每个值为i的元素出现的次数,存入数组C的第 i 项

(3)对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)

(4)反向填充目标数组:将每个元素i放在新数组的第C( i )项,每放一个元素就将C( i )减去1


二、代码实现

java 复制代码
public class CountingSort {
    public static void countingSort(int[] arr) {
        int len = arr.length;
        if (len < 2) return;
        int minVal = arr[0], maxVal = arr[0];
        for (int i = 1; i < len; i++) {
            if (arr[i] < minVal) {
                minVal = arr[i];
            } else if (arr[i] > maxVal) {
                maxVal = arr[i];
            }
        }

        int[] countArr = new int[maxVal - minVal + 1];
        for (int val : arr) {
            countArr[val - minVal]++;
        }
        for (int arrIdx = 0, countIdx = 0; countIdx < countArr.length; countIdx++) {
            while (countArr[countIdx]-- > 0) {
                arr[arrIdx++] = minVal + countIdx;
            }
        }
    }

    public static void countingSort2(int[] arr) {
        int len = arr.length;
        if (len < 2) return;
        int minVal = arr[0], maxVal = arr[0];
        for (int i = 1; i < len; i++) {
            if (arr[i] < minVal) {
                minVal = arr[i];
            } else if (arr[i] > maxVal) {
                maxVal = arr[i];
            }
        }

        int[] countArr = new int[maxVal - minVal + 1];
        for (int val : arr) {
            countArr[val - minVal]++;
        }
        for (int countIdx = countArr.length - 1, arrIdx = 0; countIdx >= 0; countIdx--) {
            while (countArr[countIdx]-- > 0) {
                arr[arrIdx++] = minVal + countIdx;
            }
        }
    }

    public static void main(String[] args) {
        int[] arr = {12, 11, 15, 50, 7, 65, 3, 99, 0};
        System.out.println("---排序前:  " + Arrays.toString(arr));
        countingSort(arr);
        System.out.println("计数排序从小到大:  " + Arrays.toString(arr));
        countingSort2(arr);
        System.out.println("计数排序从大到小:  " + Arrays.toString(arr));
    }
}

三、应用场景

  • 适用于范围较小的整数排序:计数排序适用于对范围较小的整数进行排序,因为它的时间复杂度与输入数据的范围大小线性相关,而与数据规模无关。
  • 适用于重复值较多的情况:如果输入数据中存在大量重复值,计数排序可以有效地减少比较次数,提高排序效率。
  • 稳定性:计数排序是一种稳定的排序算法,可以保持相同元素的相对顺序不变。
  • 适用于非负整数排序:计数排序要求输入数据必须是非负整数,且适用于整数排序,不适用于字符串等其他类型的数据。
  • 适用于辅助排序算法:计数排序可以作为辅助排序算法,用于优化其他排序算法的性能,例如基数排序。

参考链接:
十大经典排序算法(Java实现)

相关推荐
Code成立3 分钟前
《Java核心技术I》Swing的网格包布局
java·开发语言·swing
中草药z9 分钟前
【Spring】深入解析 Spring 原理:Bean 的多方面剖析(源码阅读)
java·数据库·spring boot·spring·bean·源码阅读
信徒_16 分钟前
常用设计模式
java·单例模式·设计模式
神仙别闹22 分钟前
基于C#实现的(WinForm)模拟操作系统文件管理系统
java·git·ffmpeg
小爬虫程序猿23 分钟前
利用Java爬虫速卖通按关键字搜索AliExpress商品
java·开发语言·爬虫
qq_4335545425 分钟前
C++ 面向对象编程:递增重载
开发语言·c++·算法
组合缺一28 分钟前
Solon v3.0.5 发布!(Spring 可以退休了吗?)
java·后端·spring·solon
程序猿零零漆30 分钟前
SpringCloud 系列教程:微服务的未来(二)Mybatis-Plus的条件构造器、自定义SQL、Service接口基本用法
java·spring cloud·mybatis-plus
猿来入此小猿32 分钟前
基于SpringBoot在线音乐系统平台功能实现十二
java·spring boot·后端·毕业设计·音乐系统·音乐平台·毕业源码
愤怒的代码1 小时前
Spring Boot对访问密钥加解密——HMAC-SHA256
java·spring boot·后端