注:代码结果显示,蓝色部分为输入,白色部分为输出
桶排序
基本思想
- 例:假设有8、5、5、3、2五个数,如何按照桶排序的方式从大到小排列?
- 第一步:分10个桶,每个桶里面是空的
- 第二步:按照数字往对应数字的桶里面放,像5有两个,则放两次
- 第三步:输出对应的值,出现了几次就打印几次
代码
ex1
import java.util.Scanner;
/**
* 桶排序
* @author Katrina
*
*/
public class ex1 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int[] a = new int[10]; //1.创建数组,初始值为0
for (int i = 0; i < 5; i++) {
int t = scanner.nextInt(); //2.循环输入5个数
a[t]++; //并进行计数
}
/* 遍历数组 */
/* 法一:从小到大 */
for (int i = 0; i < a.length; i++) { //3.判断a[0] ~ a[a.length - 1]
for (int j = 0; j < a[i]; j++) { //4.出现了几次就打印几次
System.out.print(i + " ");
}
}
System.out.println();
/* 法二:从大到小 */
for (int i = a.length - 1; i > 0; i--) {
for (int j = 0; j < a[i]; j++) {
System.out.print(i + " ");
}
}
}
}
冒泡排序
基本思想
每次比较两个相邻的元素,如果它们的顺序错误就把它们交换过来
- 例:假设有12、35、99、18、76五个数,如何按照冒泡排序的方式从大到小排列?
- 第一躺:35 99 18 76 12
- 第二趟:99 35 76 18 12
- 第三趟:99 76 35 18 12
- 第四趟:99 76 35 18 12
注:从大到小排序,越小的越靠后
代码
ex1
import java.util.Scanner;
/**
* 冒泡排序
* 思路:如果有n个数进行排序,只需将n-1个数归位,也就是说要进行n-1趟操作
* @author Katrina
*
*/
public class ex1 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt(); //1.输入n
int[] a = new int[n];
for (int i = 0; i < n; i++) {
a[i] = scanner.nextInt(); //2.读入n个数到数组a中
}
/* 冒泡排序核心部分 - 从大到小 */
int t = 0;
for (int i = 0; i < n; i++) { //3.n个数排序,只用进行n - 1趟
for (int j = 0; j < n - i - 1; j++) { //4.从第一位开始比较到最后一个尚未归位的数,注意n - i - 1
if (a[j] < a[j + 1]) { //5.比较大小并交换顺序
t = a[j];
a[j] = a[j + 1];
a[j + 1] = t;
}
}
}
for (int i = 0; i < n; i++) { //6.输出
System.out.print(a[i] + " ");
}
}
}
ex2
public class Student {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
import java.util.Scanner;
/**
* 例:
* 分别有5个人的名字和分数,按照分数从高到低,输出他们的名字
* @author Katrina
*
*/
public class ex2 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt(); //1.输入n
String[] name = new String[n];
int[] score = new int[n];
Student[] student = new Student[n];
for (int i = 0; i < n; i++) { //2.读入n个人名和分数到数组student中
name[i] = scanner.next();
score[i] = scanner.nextInt();
student[i] = new Student(name[i], score[i]);
}
/* 冒泡排序核心部分 - 按分数从高到低进行排序 */
Student stu = new Student();
for (int i = 0; i < n; i++) { //3.n个数排序,只用进行n - 1趟
for (int j = 0; j < n - i - 1; j++) { //4.从第一位开始比较到最后一个尚未归位的数,注意n - i - 1
if (student[j].getScore() < student[j + 1].getScore()) { //5.比较分数,交换数组对象的值
stu = student[j];
student[j] = student[j + 1];
student[j + 1] = stu;
}
}
}
for (int j = 0; j < student.length; j++) { //6.输出
System.out.println(student[j].getName());
}
}
}
核心:双重嵌套循环
注:
1.数组定义 int[] a = int[3]; 表示长度为3,下标取值0,1,2
2.当i = 0时候,n - i,便可以j从0取到2,j + 1使得数组越界
思考:如果使用map如何实现?
快速排序(二分)
基本思想
- 例:假设有6、1、2、7、9、3、4、5、10、8十个数,如何按照快速排序的方式从大到小排列?
- 第一步:以最左边6为基准数,分从左往右 > 6,从右往左 < 6
- 第一次交换:6 1 2 5 4 3 9 7 10 8
- 第二次交换:3 1 2 5 4 6 9 7 10 8
相遇,表示6已归位
- 第二步:从最中间6开始分为两个部分,3 1 2 5 4 和 9 7 10 8
- 第一个部分:3 1 2 5 4,以最左边为基准数,从左往右 > 3,从右往左 < 3
- 第一次交换:2 1 3 5 4
相遇,表示3已归位
- 从最中间3开始分为两个部分,2 1 和 5 4
- 最终基准数2和5归位后得,1 2 3 4 5
- 第一次交换:2 1 3 5 4
- 第二个部分:9 7 10 8,以最左边为基准数,从左往右 > 9,从右往左 < 9
- 第一次交换:9 7 8 10
- 第二次交换:8 7 9 10
相遇,表示9已归位
- 最终基准数8归为后得,7 8 9 10
- 第一个部分:3 1 2 5 4,以最左边为基准数,从左往右 > 3,从右往左 < 3
- 第一步:以最左边6为基准数,分从左往右 > 6,从右往左 < 6
注:基准数归位顺序为6、3、2、1、5、4、9、8、7、10
代码
ex1
import java.util.Scanner;
public class ex1 {
//定义全局变量
static int[] a = new int[101];
static int n;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
for (int i = 0; i < n; i++) {
a[i] = scanner.nextInt();
}
quickSort(0, n - 1); //调用快速排序
for (int i = 0; i < n; i++) {
System.out.print(a[i] + " ");
}
}
/**
* 快速排序算法
* @param left
* @param right
*/
static void quickSort(int left, int right) {
int i, j, t, temp;
if (left > right) {
return;
}
temp = a[left]; //temp中存在的就是基准数
i = left;
j = right;
while (i != j) {
//顺序很重要!先从由往左找
while (a[j] >= temp && i < j) {
j--;
}
//再从左往右找
while (a[i] <= temp && i < j) {
i++;
}
//交换两个数在数组中的位置
if (i < j) { //当哨兵i和哨兵j没有相遇时
t = a[i];
a[i] = a[j];
a[j] = t;
}
}
//最终将基准数归位
a[left] = a[i];
a[i] = temp;
quickSort(left, i - 1); //继续处理左边的,这里是一个递归的过程
quickSort(i + 1, right); //继续处理右边的,这里是一个递归的过程
return;
}
}
注:调用quickSort(0, n - 1);时候,使用的是下标值,如果0,n会出现问题,但不至于报错
小哼买书
题目说明
输入:
- 第一行正整数,表示n个同学
- 第二行为每本书的ISBN号
输出:
- 第一行正整数,去重后需要买多少本书
- 第二行为每本书的ISBN号
基本思路
法一:
先将这n个图书的ISBN号去重,再进行从小到大排序并输出
法二:
先从小到大排序(使用冒泡排序或者快速排序),输出的时候再去重
代码
法一:
- 桶排序
import java.util.Scanner;
/**
* 法一:去重(标记,判断出现一次的即可) + 桶排序
* @author Katrina
*
*/
public class ex1 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int[] a = new int[1001];
for (int i = 0; i < a.length; i++) {
a[i] = 0; //初始化
}
int n = scanner.nextInt(); //读入n
for (int i = 0; i < n; i++) { //循环读入n个图书的ISBN号
int t = scanner.nextInt(); //把每一个ISBN号读到变量t中
a[t] = 1; //标记出现过的ISBN号
}
for (int i = 0; i < a.length; i++) { //依次判断1 ~ 1000这个1000桶
if (a[i] == 1) { //如果这个ISBM号出现过则打印出来
System.out.print(i + " ");
}
}
}
}
法二:
- 冒泡排序
import java.util.Scanner;
/**
* 法二:冒泡排序 + 去重(判断a[i]与a[i-1]是否相同)
* @author Katrina
*
*/
public class ex2 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int[] a = new int[101];
int n = scanner.nextInt(); //读入n
for (int i = 0; i < n; i++) { //循环读入n个图书ISBN号
a[i] = scanner.nextInt();
}
/* 冒泡排序 */
int t = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n - i -1; j++) {
if (a[j] > a[j + 1]) {
t = a[j];
a[j] = a[j + 1];
a[j + 1] = t;
}
}
}
System.out.print(a[0] + " "); //输出第1个数
for (int i = 1; i < n; i++) { //从2循环到n
if (a[i] != a[i - 1]) { //如果当前这个数是第一次出现则输出
System.out.print(a[i] + " ");
}
}
}
}
法三:
- 快速排序
import java.util.Scanner;
/**
* 法三:快速排序 + 去重(判断a[i]与a[i-1]是否相同)
* @author Katrina
*
*/
public class ex3 {
static int[] a = new int[101];
static int n;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
for (int i = 0; i < n; i++) {
a[i] = scanner.nextInt();
}
quickSort(0, n - 1); //调用快速排序
System.out.print(a[0] + " ");
for (int i = 1; i < n; i++) {
if (a[i] != a[i - 1]) {
System.out.print(a[i] + " ");
}
}
}
/**
* 快速排序算法
* @param left
* @param right
*/
static void quickSort(int left, int right) {
int i, j, t, temp;
if (left > right) {
return;
}
temp = a[left]; //temp中存在的就是基准数
i = left;
j = right;
while (i != j) {
while (a[j] >= temp && i < j) {
j--;
}
while (a[i] <= temp && i < j) {
i++;
}
if (i < j) {
t = a[i];
a[i] = a[j];
a[j] = t;
}
}
a[left] = a[i];
a[i] = temp;
quickSort(left, i - 1);
quickSort(i + 1, right);
return;
}
}
总结
时间复杂度
桶排序O(N + M) > 快速排序O(NlogN) > 冒泡排序O( N 2 N^{2} N2)