什么是计数排序?

news/2024/11/29 8:43:46/

计数排序、基数排序、桶排序,这几种排序算法,可能大家见到的这次不多,有些大学的教材课本中,甚至有些都没有计数排序算法。

所以呢,帅地今天就简单讲一讲计数排序算法吧,而不会像前面一样长篇大论,因为我觉得,每一个学习计数排序的,应该都是有一定的算法基础了,而对于计数排序,我觉得大家掌握最基本的思想就可以了,平时做算法题的时候,还是会偶尔用到。

当然,计数排序如果要深入讲解,其实也是可以比较复杂的,但是这里,帅地只讲最简洁的,因为我觉得了解了基础的,就差不多了。

举个例子,假如我要给如下这个数组排序,你会如何排序呢?

输入 arr[] = {9,3,5,4,9,1,2,7,8,1,3,6,5,3,4,0,10,9 ,7,9}。

如果用快速排序,归并排序等这些排序算法的话,那么他们的时间复杂度其实是 O(nlogn)。

那么有没有一种方法,使得它的时间复杂度是 O(n) 呢?

答是有的,那便是计数排序

计数排序的基本思想是这样的:把数组元素作为数组的下标,然后用一个临时数组统计该元素出现的次数,例如 temp[i] = m, 表示元素 i 一共出现了 m 次。最后再把临时数组统计的数据从小到大汇总起来,此时汇总起来是数据是有序的。

例如对于上面那个例子,我们可以创建一个数组大小为 11 的临时数组 temp

图片

因为数组的最大值是 10,所以临时数组的最大下标为 10 即可。

然后遍历数组,第一个整数是9,那么数组下标为9的元素加1:

图片

第二个整数是3,那么数组下标为3的元素加1:

图片

最终,数列遍历完毕时,数组的状态如下:

图片

之后我们只需要遍历临时数组 temp,输出临时数组元素的下标值即可,元素的值是几,就输出几次,结果如下:

0,1,1,2,3,3,3,4,4,5,5,6,7,7,8,9,9,9,9,10

显然,这个输出的数列已经是有序的了。

Java 代码如下(代码会做详细的注释)

   public static int[] countSort(int[] arr) {if(arr == null || arr.length < 2) return arr;int n = arr.length;int max = arr[0];// 寻找数组的最大值,该值用来创建临时数组用的for (int i = 1; i < n; i++) {if(max < arr[i])max = arr[i];}//创建大小为max + 1的临时数组int[] temp = new int[max + 1];//统计元素i出现的次数for (int i = 0; i < n; i++) {temp[arr[i]]++;}int k = 0;//把临时数组统计好的数据汇总到原数组for (int i = 0; i <= max; i++) {// temp[i] 的值表示元素 i 出现的次数for (int j = temp[i]; j > 0; j--) {arr[k++] = i;}}return arr;}

优化一下

上面的代码中,我们是根据 max 的大小来创建对应大小的数组,假如原数组只有 10 个元素,并且最小值为 min = 10000,最大值为 max = 10005,那我们创建 10005 + 1 大小的数组不是很吃亏?最大值与最小值的差值为 5,所以我们创建大小为 6 的临时数组就可以了,这样可以节省空间浪费

也就是说,我们创建的临时数组大小 (max - min + 1)就可以了,然后我们再把 min作为偏移量。优化之后的代码如下所示:

    public static int[] sort(int[] arr) {if(arr == null || arr.length < 2) return arr;int n = arr.length;int min = arr[0];int max = arr[0];// 寻找数组的最大值与最小值for (int i = 1; i < n; i++) {if(max < arr[i])max = arr[i];if(min > arr[i])min = arr[i];}int d = max - min + 1;//创建大小为max的临时数组int[] temp = new int[d];//统计元素i出现的次数for (int i = 0; i < n; i++) {temp[arr[i] - min]++;}int k = 0;//把临时数组统计好的数据汇总到原数组for (int i = 0; i < d; i++) {// temp[i] 的值表示元素 i 出现的次数for (int j = temp[i]; j > 0; j--) {arr[k++] = i + min;}}return arr;}

我这里还给大家准备了一个动画,大家看看就好

image-20230213174646813

有人可能会问,如果数组只有十个元素,最小值为 min = 0,最大值 max = 1000000。那我不是得创建一个 大小为 1000000 的数组?

或者说,如果我数组中有浮点数,那不就是无法作为下标来使用了?

别问,问就是,每一种排序算法都有它的局限性,不然还用啥快速排序,目前用的最广的感觉还是快速排序,想计数排序这种,适用特定领域数据下的排序,例如最大值和最小值的差值不是很大的整数数组。

更多排序算法文章

1. 漫画:什么是冒泡排序算法?

2. 漫画:什么是选择排序算法?

3. 漫画:什么是插入排序算法?

4. 漫画:什么是希尔排序算法?

5. 漫画:什么是归并排序算法?

6. 漫画:什么是快速排序算法?

7. 漫画:什么是堆排序算法?

8. 漫画:什么是基数排序算法?

9. 漫画:什么是外部排序?

10. 什么是计数排序?

11. 十大排序算法极简汇总篇

推荐阅读

下载破 2w+,在校生必看,《程序员内功修炼》第二版出炉

从双非到大厂,帅地写了一本原创PDF送给大家

一个帮你拿offer的校招网站

算法刷题路线(系统+全面)

作者简介:我是帅地,校招拿到过不少大厂offer,毕业去了腾讯研发岗,毕业半年整到人生第一个 100 万,目前专注于写大学规划 + 校招求职相关的内容,著有个人原创网站 PlayOffer。


http://www.ppmy.cn/news/32662.html

相关文章

用ChatGPT编写的一个调用ElasticSearch的maven的spring elasticsearch demo案例

以下是一个简单的Maven工程和Spring demo案例&#xff0c;演示如何使用Java调用Elasticsearch。 配置Maven依赖 在pom.xml文件中添加以下依赖&#xff1a; org.elasticsearch elasticsearch 6.5.4 org.elasticsearch.client transport 6.5.4 org.elasticsearch.client rest 6…

js正则:input 输入限制

这里写自定义目录标题正则&#xff1a;input 输入限制&#xff08;IP和数值类型规则限制输入&#xff09;核心方法 input 输入框的 oninput 监听事件1、IP输入检验及限制2、数值&#xff08;含负数、保留两位&#xff09;输入检验及限制正则&#xff1a;input 输入限制&#xf…

【数据结构与算法】双向带头循环链表(附源码)

目录 一.前言 二.双向带头循环链表的结构 三.接口实现 A.初始化 ListNodeinit 和销毁 Listdestroy 1.ListNodeinit 2.Listdestroy B.插入 1.头插 ListNodepushfront 2.尾插 ListNodepushback 3.插入 ListNodeinsert C.删除 1.头删 ListNodepopfront 2.尾删 ListN…

CSS实现一个展示框

&#x1f31f;所属专栏&#xff1a;前端只因变凤凰之路&#x1f414;作者简介&#xff1a;rchjr——五带信管菜只因一枚&#x1f62e;前言&#xff1a;该系列将持续更新前端的相关学习笔记&#xff0c;欢迎和我一样的小白订阅&#xff0c;一起学习共同进步~&#x1f449;文章简…

fs 模块

fs 全称为 file system &#xff0c;称之为 文件系统 &#xff0c;是 Node.js 中的 内置模块 &#xff0c;可以对计算机中的磁盘进行操作。本章节会介绍如下几个操作&#xff1a;1. 文件写入2. 文件读取3. 文件移动与重命名4. 文件删除5. 文件夹操作6. 查看资源状态一、文件写入…

C++【list容器模拟实现函数解析】

list容器&&模拟实现函数解析 文章目录list容器&&模拟实现函数解析一、list容器使用介绍二、list容器模拟实现及函数解析2.1 list结构体创建2.2 迭代器封装2.21 构造函数&#xff1a;2.22 前置和后置及- -2.23 解引用2.24 判断相等2.25 箭头重载2.26 第二个和第…

Qss样式表语法

QSS样式表语法 更多精彩内容&#x1f449;个人内容分类汇总 &#x1f448;&#x1f449;QSS样式学习 &#x1f448;文章目录QSS样式表语法[toc]概述一、样式规则二、选择器类型三、子控件四、伪状态五、样式表冲突解决六、级联七、继承八、命名空间中的控件概述 Qt样式表的概念…

2021蓝桥杯真题公约数(填空题) C语言/C++

题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 如果整数 a 是整数 b 的整数倍&#xff0c;则称 b 是 a 的约数。 请问&#xff0c;有多少个正整数既是 2020 的约数&#xff0c;又是 3030 的约数。 运行限制 最大…