【Java】《啊哈算法》-第一章排序

本文对比了桶排序、冒泡排序和快速排序在实例中的应用,介绍了各自的基本思想,并探讨了它们的时间复杂度:桶排序O(N+M)、快速排序O(NlogN)和冒泡排序O(N^2)。通过代码演示,展示了如何按从大到小的顺序对数字进行排序,以及如何在实际场景中去重和应用。
摘要由CSDN通过智能技术生成

注:代码结果显示,蓝色部分为输入,白色部分为输出

桶排序

基本思想

  • 例:假设有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
          • 最终基准数25归位后得,1 2 3 4 5
      • 第二个部分:9 7 10 8,以最左边为基准数,从左往右 > 9,从右往左 < 9
        • 第一次交换:9 7 8 10
        • 第二次交换:8 7 9 10 相遇,表示9已归位
          • 最终基准数8归为后得,7 8 9 10

注:基准数归位顺序为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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值