缘起
各位大哥大姐,兄弟姐妹们好呀!本人最近看了下《啊哈算法》,说来惭愧,买几年了,当初看了一会儿就吃灰了。
不过写的确实蛮好的,生动形象,精准有趣。
但稍显遗憾的是,书籍示例代码是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
即可!
案例
按照本书,给出了一个案例:
小哼的学校要建立一个图书角,老师派小哼去找一些同学做调查,看看同学们都喜欢读哪些书。小哼让每个同学写出一个自己最想读的书的ISBN号(你知道吗?每本书都有唯一的ISBN号,不信的话你去找本书翻到背面看看)。当然有一些好书会有很多同学都喜欢,这样就会收集到很多重复的ISBN号。小哼需要去掉其中重复的ISBN号,即每个ISBN号只保留一个,也就说同样的书只买一本(学校真是够抠门的)。然后再把这些ISBN号从小到大排序,小哼将按照排序好的ISBN号去书店买书。请你协助小哼完成 “
去重
” 与 “排序
” 的工作。
当然,我们这里为了方便,做一下输入限制:
输入有2行,
第1行为一个正整数,表示有n个同学参与调查(n≤100)。
第2行有n 个用空格隔开的正整数,为每本图书的ISBN号(假设图书的ISBN号在1~1000之间)。
然后我们需要输出:
输出也是 2 行,
第 1 行为一个正整数 k,表示需要买多少本书。
第 2 行为 k 个用空格隔开的正整数,为从小到大已排好序的需要购买的图书的 ISBN 号。
根据题目,我们不难得出,题目分为 去重、 排序和 计数 三步。那么这道题用三种排序算法要怎么做呢?
我们来分析一下:
- 如果是用桶排序的话,我们直接入桶的同时并计数,然后输出有元素的桶就好。
- 如果使用冒泡排序或者快速排序的话,需要先升序排序,然后再判断是否有重复的元素并计数。
话不多说,下面直接上代码,具体解释看代码注释就好了。
桶排序
核心代码:
/**
* @Description 桶排序 - 去重
* @Param [arr: 待去重排序后的数组]
* @return
**/
private static void bucketSort(int[] arr) {
int count = 0; // 声明变量,用于计数
int[] bucket = new int[1001];
for (int i : arr) { // 遍历数组
if(bucket[i] == 0) { // 计数
count++;
}
bucket[i]++; // 入桶
}
System.out.println("需要买书的本数为: " + count);
System.out.print("得到去重排序后的ISBN号数组为: ");
for (int i = 0; i < 1001; i++) { // 遍历桶
if (bucket[i] > 0) { // 桶内有数,则输出桶
System.out.print(i + " ");
}
}
// 换行
System.out.println();
}
完整代码:
package com.guqueyue.aHaAlgorithm.chapter_1_Sort;
import java.util.Scanner;
/**
* @Author: guqueyue
* @Description: 小哼买书,去书籍的ISBN号进行去重排序
* @Date: 2024/1/10
**/
public class BuyBook {
public static void main(String[] args) {
// 获取书籍的ISBN号
int[] arr = getArr();
// 桶排序
bucketSort(arr);
}
/**
* @Description 桶排序 - 去重
* @Param [arr: 待去重排序后的数组]
* @return
**/
private static void bucketSort(int[] arr) {
int count = 0; // 声明变量,用于计数
int[] bucket = new int[1001];
for (int i : arr) { // 遍历数组
if(bucket[i] == 0) { // 计数
count++;
}
bucket[i]++; // 入桶
}
System.out.println("需要买书的本数为: " + count);
System.out.print("得到去重排序后的ISBN号数组为: ");
for (int i = 0; i < 1001; i++) { // 遍历桶
if (bucket[i] > 0) { // 桶内有数,则输出桶
System.out.print(i + " ");
}
}
// 换行
System.out.println();
}
/**
* @Description 获取书籍的ISBN号
* @Param []
* @return int[]
**/
private static int[] getArr() {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入书籍数: ");
int n = scanner.nextInt();
int[] arr = new int[n];
System.out.printf("请输入第%d本书的ISBN号(0-1000), 中间用空格隔开,再回车:", n);
for (int i = 0; i < n; i++) {
arr[i] = scanner.nextInt();
}
return arr;
}
}
演示:
大功告成!
冒泡排序
冒泡排序跟桶排序不同的是,它是先排序,再进行去重和计数,
而其中排序的代码跟之前的博客的内容别无二致,但是需要增加去重和计数的代码:
// 去重计数
int count = 1;
String str = arr[0] + " "; // 保存第一个数
for (int i = 1; i < arr.length; i++) {
if (arr[i] != arr[i-1]) { // 与前一个不相等则存起来方便输出
str += arr[i] + " ";
count++; // 计数
}
}
// 输出
System.out.println("需要买书的本数为: " + count);
System.out.println("得到去重排序后的ISBN号数组为: " + str);
完整代码:
package com.guqueyue.aHaAlgorithm.chapter_1_Sort;
import java.util.Arrays;
import java.util.Scanner;
/**
* @Author: guqueyue
* @Description: 小哼买书,去书籍的ISBN号进行去重排序 - 冒泡排序
* @Date: 2024/1/10
**/
public class BuyBook2 {
public static void main(String[] args) {
// 获取书籍的ISBN号
int[] arr = getArr();
// 冒泡排序
bubbleSort(arr);
System.out.println("得到排序后的ISBN号数组为: " + Arrays.toString(arr));
// 去重计数
int count = 1;
String str = arr[0] + " "; // 保存第一个数
for (int i = 1; i < arr.length; i++) {
if (arr[i] != arr[i-1]) { // 与前一个不相等则存起来方便输出
str += arr[i] + " ";
count++; // 计数
}
}
// 输出
System.out.println("需要买书的本数为: " + count);
System.out.println("得到去重排序后的ISBN号数组为: " + str);
}
/**
* @Description 冒泡排序
* @Param [arr]
* @return int[]
**/
private static void bubbleSort(int[] arr) {
int n = arr.length;
for (int i = 0; i < n - 1; i++) { // 交换
for (int j = 1; j < n-i; j++) {
if (arr[j] < arr[j-1]) {
int t = arr[j]; arr[j] = arr[j-1]; arr[j-1] = t;
}
}
}
}
/**
* @Description 获取书籍的ISBN号
* @Param []
* @return int[]
**/
private static int[] getArr() {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入书籍数: ");
int n = scanner.nextInt();
int[] arr = new int[n];
System.out.printf("请输入第%d本书的ISBN号(0-1000), 中间用空格隔开,再回车:", n);
for (int i = 0; i < n; i++) {
arr[i] = scanner.nextInt();
}
return arr;
}
}
运行代码,控制台输入,可得:
快速排序
快速排序跟冒泡排序类似,都是先排序,再进行去重和计数,无非是排序的算法发生了变化:
package com.guqueyue.aHaAlgorithm.chapter_1_Sort;
import java.util.Arrays;
import java.util.Scanner;
/**
* @Author: guqueyue
* @Description: 小哼买书,去书籍的ISBN号进行去重排序 - 快速排序
* @Date: 2024/1/10
**/
public class BuyBook3 {
public static void main(String[] args) {
// 获取书籍的ISBN号
int[] arr = getArr();
// 快速排序
quickSort(arr, 0, arr.length-1);
System.out.println("得到排序后的ISBN号数组为: " + Arrays.toString(arr));
// 去重计数
int count = 1;
String str = arr[0] + " "; // 保存第一个数
for (int i = 1; i < arr.length; i++) {
if (arr[i] != arr[i-1]) { // 与前一个不相等则存起来方便输出
str += arr[i] + " ";
count++; // 计数
}
}
// 输出
System.out.println("需要买书的本数为: " + count);
System.out.println("得到去重排序后的ISBN号数组为: " + str);
}
/**
* @Description 快速排序
* @Param [arr, left, right]
* @return void
**/
private static void quickSort(int[] arr, int left, int right) {
if (left >= right) {
return;
}
int i = left, j = right, temp = arr[left]; // temp为基准值
while (i < j) { // 相遇了就不能继续找了
// 右边的先找
while (arr[j] >= temp && i < j) {
j--;
}
// 左边的后找
while (arr[i] <= temp && i < j) {
i++;
}
// 如果没有相遇,则交换
if (i < j) {
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
// 交换基准值
arr[left] = arr[i];
arr[i] = temp;
// 继续左边找
quickSort(arr, left, i-1);
// 继续右边找
quickSort(arr, i+1, right);
}
/**
* @Description 获取书籍的ISBN号
* @Param []
* @return int[]
**/
private static int[] getArr() {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入书籍数: ");
int n = scanner.nextInt();
int[] arr = new int[n];
System.out.printf("请输入第%d本书的ISBN号(0-1000), 中间用空格隔开,再回车:", n);
for (int i = 0; i < n; i++) {
arr[i] = scanner.nextInt();
}
return arr;
}
}
启动程序,输入可得:
完美!!!