Java玩转《啊哈算法》排序之桶排序

过去心不可得,现在心不可得,未来心不可得

目录在这里

  • 楔子
  • 代码地址
  • 桶排序
  • 代码
    • 核心部分
      • 优缺点
    • 完整代码
    • 演示
  • 升级版
    • 核心代码
    • 完整代码
    • 演示

楔子

大家好!本人最近看了下《啊哈算法》,写的确实不错,生动形象又有趣(我没收钱,确实如此 )。

但对我来说,稍显遗憾的是,书籍代码是c语言,而不是本人常用的Java。

那就弥补遗憾,说干就干,把这本书的示例语言用java给翻译一遍!!!

于是就有了本篇博客,当然这只是第一篇,主要是讲解桶排序。
在这里插入图片描述

没有买纸质书的童鞋也甭担心,电子版的下载链接已经放到下方了,自己下载去吧!!!

链接:https://pan.baidu.com/s/1imxiElcCorw2F-HJEnB-PA?pwd=jmgs
提取码:jmgs

不过还是建议有条件的同学可以买下纸质书,尊重一下作者的劳动成果。

代码地址

本文代码已开源:

git clone https://gitee.com/guqueyue/my-blog-demo.git

请切换到gitee分支,

然后查看aHaAlgorithm模块下的src/main/java/com/guqueyue/aHaAlgorithm/chapter_1_Sort即可!

桶排序

算法学习千千万,排序是块敲门砖!!!

国内算法学习似乎有个不成文的规定,想学算法,先学排序。而桶排序可以说是排序算法中最简单的算法了。

在这里插入图片描述

桶排序的核心原理非常简单:

遍历需要排序的元素集合,用一个数组表示。数组的一个个连续的空间作为一个个桶,索引为元素,而索引对应的值为元素个数。

相当于把元素放到对应的一个一个桶里面,所以叫桶排序。
在这里插入图片描述

而因为数组的索引是连续的,所以遍历数组索引就能得到一个升序的元素集合。如果索引对应的值为0,说明该元素不存在。

代码

核心部分

	/*** @Description 桶排序* @Param [scoreArr]* @return int[]**/private static int[] bucketSort(int[] scoreArr) {// 11为数据范围的大小int[] bucket = new int[11];// 用于返回排序后的数组int[] result = new int[scoreArr.length];// 入桶,计数for (int num : scoreArr) {bucket[num]++;}// 根据桶的索引以及计数的次数,生成排序后的数组 - 如果需要降序,倒序遍历数组即可int k = 0;for (int i = 0; i < bucket.length; i++) { // 遍历每个桶for (int j = 0; j < bucket[i]; j++) { // 遍历桶里面的元素result[k++] = i;}}return result;}

优缺点

通过上文的讲解以及核心代码,我们不难得出桶排序具有以下的优缺点:

  • 优点:
    1. 简单
    2. 速度快。时间复杂度为:O(m+n), 其中m为排序数组的大小,n为桶的大小。
  • 缺点:
    1. 占用空间。因为桶的长度取决于元素的取值范围,元素的取值范围越大,越占用空间。
    2. 有使用局限,只能对整数进行排序。若元素中存在小数无法使用桶排序,因为数组的索引不能为小数。

完整代码

package com.guqueyue.aHaAlgorithm.chapter_1_Sort;import java.util.Arrays;
import java.util.Scanner;/*** @Author: guqueyue* @Description: 桶排序* @Date: 2024/1/8**/
public class BucketSort {public static void main(String[] args) {// 获取分数数组int[] scoreArr = getScoreArr();System.out.println("输入的数组为: " + Arrays.toString(scoreArr));// 桶排序int[] result = bucketSort(scoreArr);System.out.println("排序后:" + Arrays.toString(result));}/*** @Description 桶排序* @Param [scoreArr]* @return int[]**/private static int[] bucketSort(int[] scoreArr) {// 11为数据范围的大小int[] bucket = new int[11];// 用于返回排序后的数组int[] result = new int[scoreArr.length];// 入桶,计数for (int num : scoreArr) {bucket[num]++;}// 根据桶的索引以及计数的次数,生成排序后的数组 - 如果需要降序,倒序遍历数组即可int k = 0;for (int i = 0; i < bucket.length; i++) { // 遍历每个桶for (int j = 0; j < bucket[i]; j++) { // 遍历桶里面的元素result[k++] = i;}}return result;}/*** @Description 获取分数数组* @Param []* @return int[]**/private static int[] getScoreArr() {Scanner scanner = new Scanner(System.in);System.out.print("请输入数组长度:");int n = scanner.nextInt();int[] scoreArr = new int[n];for (int i = 0; i < n; i++) {System.out.printf("请输入第%d个数(范围:0-10),然后按回车: ", i+1);scoreArr[i] = scanner.nextInt();}return scoreArr;}
}

演示

运行代码,控制台输入可得:
在这里插入图片描述

升级版

正如作者所说,上文演示的只是一个简易版的桶排序算法。

那如果需要输入多个学生的姓名和分数,再根据学生的分数排名由高到低输出学生的姓名,这样要怎么做呢?

作者这里并没有给出答案,我们来扩展一下,首先创建一个学生类:

package com.guqueyue.aHaAlgorithm.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @Author: guqueyue* @Description: 学生类* @Date: 2024/1/9**/
//lombok插件的注解
@Data // 若未使用lombok插件,请自行生成getter、setter以及toString方法
@NoArgsConstructor // 若未使用lombok插件,请自行生成无参构造方法
@AllArgsConstructor // 若未使用lombok插件,请自行生成有参构造方法
public class Student {private String name; // 姓名private Integer score; // 分数
}

核心代码

同理,我们使用桶排序,得到一个通过分数降序排序的学生数组:

	/*** @Description 桶排序 - 通过分数排序学生数组* @Param [scoreArr]* @return com.guqueyue.aHaAlgorithm.entity.Student[]**/private static Student[] bucketSort(Student[] scoreArr) {Student[] result = new Student[scoreArr.length];// 桶排序,将分数入桶int[] bucket = new int[101];for (Student student : scoreArr) {bucket[student.getScore()]++;}int k = 0;for (int i = 100; i >= 0; i--) { // 倒序遍历桶if (bucket[i] > 0) {for (Student student : scoreArr) { // 遍历学生数组,将符合当前桶的分数的学生放入数组if (student.getScore() == i) {result[k++] = student;}}}}return result;}

完整代码

package com.guqueyue.aHaAlgorithm.chapter_1_Sort;import com.guqueyue.aHaAlgorithm.entity.Student;import java.util.*;/*** @Author: guqueyue* @Description: 桶排序 - 通过分数排序学生数组* @Date: 2024/1/9**/
public class BucketSort2 {public static void main(String[] args) {Student[] scoreArr = getStudentArr(); // 获取学生数组System.out.println("输入的数组为:" + Arrays.toString(scoreArr));Student[] result = bucketSort(scoreArr);System.out.println("排序后的数组为: " + Arrays.toString(result));System.out.print("学生排名为: ");for (Student student : result) {System.out.print(student.getName() + " ");}System.out.println();}/*** @Description 桶排序 - 通过分数排序学生数组* @Param [scoreArr]* @return com.guqueyue.aHaAlgorithm.entity.Student[]**/private static Student[] bucketSort(Student[] scoreArr) {Student[] result = new Student[scoreArr.length];// 桶排序,将分数入桶int[] bucket = new int[101];for (Student student : scoreArr) {bucket[student.getScore()]++;}int k = 0;for (int i = 100; i >= 0; i--) { // 倒序遍历桶if (bucket[i] > 0) {for (Student student : scoreArr) { // 遍历学生数组,将符合当前桶的分数的学生放入数组if (student.getScore() == i) {result[k++] = student;}}}}return result;}/*** @Description 桶排序优化版 - 通过分数排序学生数组* @Param [scoreArr]* @return com.guqueyue.aHaAlgorithm.entity.Student[]**/private static Student[] bucketSort2(Student[] scoreArr) {// 1.构建 分数 -> 人名集合 映射集Map<Integer, List<Student>> dict = new HashMap<>();for (Student student : scoreArr) {Integer score = student.getScore();List<Student> studentList = new ArrayList<>();if (dict.containsKey(score)) {studentList = dict.get(score);}studentList.add(student);dict.put(score, studentList);}Student[] result = new Student[scoreArr.length];// 桶排序int[] bucket = new int[101];for (Student student : scoreArr) {bucket[student.getScore()]++;}int k = 0;for (int i = 100; i >= 0; i--) {if (bucket[i] > 0) { // 如果有List<Student> students = dict.get(i);if (students != null && students.size() > 0) {for (Student student : students) {result[k++] = student;}}}}return result;}/*** @Description 获取学生数组* @Param []* @return com.guqueyue.aHaAlgorithm.entity.Student[]**/private static Student[] getStudentArr() {Scanner scanner = new Scanner(System.in);System.out.print("请输入学生数量:");int n = scanner.nextInt();Student[] students = new Student[n];for (int i = 0; i < n; i++) {Student student = new Student();System.out.printf("请输入第%d个学生的姓名:", i+1);student.setName(scanner.next());System.out.printf("请输入第%d个学生的分数(0-100):", i+1);student.setScore(scanner.nextInt());students[i] = student;}return students;}
}

演示

运行代码,控制台输入,可得:
在这里插入图片描述

我们下期博客再见!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/644687.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Optional的使用(代替if判断是否为空)

Optional 前言 我的使用 package yimeng;import com.ruoyi.RuoYiApplication; import com.ruoyi.common.core.domain.entity.SysUser; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import java.util.*;SpringBootTes…

OpenCV第 2 课 OpenCV 环境搭建

文章目录 第 2 课 OpenCV 环境搭建1.安装 Numpy2.从 Ubuntu 存储库安装 OpenCV3.验证 OpenCV 安装 第 2 课 OpenCV 环境搭建 1.安装 Numpy 每一张图像都有很多个像素点&#xff0c;这也导致了程序中会涉及大量的数组处理。Numpy 是一个 Python 的拓展库&#xff0c;它对多维数…

mysql临时表简述

概述 业务中经常会对一些表进行聚合组装信息&#xff0c;然后筛选&#xff0c;有些表比较数据量大的时候&#xff0c;会对拖慢查询&#xff1b; 常用的mybatis的分页查询&#xff0c;在查询时会先count一下所有数据&#xff0c;然后再limit分页&#xff0c;即使分页也会有深度…

数据分析-Pandas如何用图把数据展示出来

数据分析-Pandas如何用图把数据展示出来 俗话说&#xff0c;一图胜千语&#xff0c;对人类而言一串数据很难立即洞察出什么&#xff0c;但如果展示图就能一眼看出来门道。数据整理后&#xff0c;如何画图&#xff0c;画出好的图在数据分析中成为关键的一环。 数据表&#xff…

「JavaSE」抽象类接口2

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;快来卷Java啦 &#x1f387;欢迎点赞收藏加关注哦&#xff01; 抽象类&接口2 &#x1f349;接口间的继承&#x1f349;接口的应用&#x1f349;总结 &#x1f349;接口间的继承 和类的继承…

【每日一题】最长交替子数组

文章目录 Tag题目来源解题思路方法一&#xff1a;双层循环方法二&#xff1a;单层循环 写在最后 Tag 【双层循环】【单层循环】【数组】【2024-01-23】 题目来源 2765. 最长交替子数组 解题思路 两个方法&#xff0c;一个是双层循环&#xff0c;一个是单层循环。 方法一&am…

yarn集群HDFS datanode无法启动问题排查

一、问题场景 hdfs无法访问&#xff0c;通过jps命令查看进程&#xff0c;发现namenode启动成功&#xff0c;但是所有datanode都没有启动&#xff0c;重启集群&#xff08;start-dfs.sh&#xff09;后仍然一样 二、原因分析 先看下启动的日志有无报错。打开Hadoop的日志目录 …

线程池中线程数量与队列大小参数的如何设置实践-基于QPS的计算公式

目录 概要 传统方式? 线程池理解? 基于QPS的设置思路? 总结? 概要 线程池是个既靠谱但又陌生的家伙, 像管家一样, 会踏踏实实的把你交代的任务完成, 但很死板, 没有自动安排人的能力, 需要你给它配好人手(线程实例)和承载容量(队列大小), 这些参数关系影响业务服务整体…

rabbitmq基础-java-5、Topic交换机

1、简介 Topic类型的Exchange与Direct相比&#xff0c;都是可以根据RoutingKey把消息路由到不同的队列。 只不过Topic类型Exchange可以让队列在绑定BindingKey 的时候使用通配符&#xff01; BindingKey 一般都是有一个或多个单词组成&#xff0c;多个单词之间以.分割&#x…

使用Python的pygame库实现迷宫游戏

使用Python的pygame库实现迷宫游戏 关于Python中pygame游戏模块的安装使用可见 https://blog.csdn.net/cnds123/article/details/119514520 先给出效果图&#xff1a; 这个游戏能自动生成迷宫布局。 在这个游戏中&#xff0c;玩家将使用键盘箭头键来移动&#xff0c;并且目标…

深入了解达梦数据库的增删查改操作:从入门到精通

目录 前言&#xff1a; 一.达梦数据库的增删改查 1.创建数据库 2.插入数据 3.查看数据 4.删除数据 5.数据 前言&#xff1a; 在当今数字化的时代&#xff0c;数据库已经成为企业和组织的核心资产&#xff0c;是实现高效数据处理、存储和管理的重要工具。达梦数据库&…

测试用例评审流程

1:评审的过程 A:开始前做好如下准备 1、确定需要评审的原因 2、确定进行评审的时机 3、确定参与评审人员 4、明确评审的内容 5、确定评审结束标准 6、提前至少一天将需要评审的内容以邮件的形式发送给评审会议相关人员。并注明详审时间、地点及偿参与人员等。 7、 在邮件中提醒…

科创板交易规则科普

一、交易时间&#xff1a; 交易日的上午9:30-11:30&#xff0c;下午13:00-15:00&#xff0c;其中9:15-9&#xff1a;25是开盘价公布以及竞价的时间&#xff0c;15:05-15:30是盘后固定价格交易时间。 二、买卖原则&#xff1a; 科创板实行T1交易&#xff0c;按照市场实时价格…

Linux运维实战:CentOS7.6操作系统(Shell脚本基础)

文章目录 第19章 Shell脚本基础19.1 Shell基本语法19.1.1 什么是Shell19.1.2 编程语言分类1.低级语言2.高级语言19.1.3 什么是Shell脚本19.2 Shell变量及运用19.2.1 Shell变量1.变量的设置规则如下2.按照变量的作用可以分成以下4类3.按照变量的作用域可以把变量分成两类:…

音乐证书通过率发布,市场对持有者需求旺盛

音乐证书的考试难度备受关注&#xff0c;通过率终于揭晓。据官方公布的数据&#xff0c;该证书的通过率相对较低&#xff0c;需要考生在音乐技能和表现方面有出色的表现。然而&#xff0c;持有音乐证书的人才在市场上需求旺盛&#xff0c;各种音乐机构和企业对其表现出强烈兴趣…

SpringBoot整合ElasticSearch实现分页查询

本文使用SpringBoot整合ElasticSearch实现分页查询 文章目录 环境准备分页查询方式一方式二 本文小结 环境准备 还是继续使用spring-boot-starter-data-elasticsearch来实现分页查询操作 <!-- spring-boot-starter-data-elasticsearch--> <dependency><groupId&…

基于SpringBoot + vue 的旅游景区网站系统设计与实现

目录 一、需求分析 二、技术分析 三、功能分析 四、数据设计 五、界面展示 六、资源获取 一、需求分析 旅游推荐网站是指提供旅游相关信息、服务和建议的在线平台。这些网站旨在帮助用户规划和安排旅行&#xff0c;提供目的地信息、酒店预订、机票预订、租车服务、旅行建…

antv/g6绘制数据流向图

antv/g6绘制数据流向图 前言接口模拟数据htmlts页面效果 前言 在业务开发中需要绘制数据流向图&#xff0c;由于echarts关系图的限制以及需求的特殊要求&#xff0c;转而使用antv/g6实现&#xff0c;本文以代码的方式实现数据流向需求以及节点分组,版本"antv/g6": “…

从零学习开发一个RISC-V操作系统(四)丨RISC-V汇编语言编程

本篇文章的内容 一、RISC-V汇编语言简介1.1 RISC-V 汇编语言的基本格式1.2 RISC-V 汇编指令操作对象1.3 RISC-V 汇编指令编码格式1.4 RISC-V 汇编指令分类 二、RISC-V汇编语言详解2.1 add 加法指令2.2 sub 减法指令 本系列是博主参考B站课程学习开发一个RISC-V的操作系统的学习…

linux条件判断练习

1.实现自动生成相应的压缩包 1.写一个脚本&#xff0c;完成如下功能 传递一个参数给脚本&#xff0c;此参数为gzip、bzip2或者xz三者之一&#xff1b; (1) 如果参数1的值为gzip&#xff0c;则使用tar和gzip归档压缩/etc目录至/backups目录中&#xff0c;并命名为/backups/etc-…