数据结构与算法-选择冒泡快排计数

news2024/10/11 0:33:27

    一:选择排序

    场景:找出一个班上身高最高的人你会怎么找?A B C D A B

选择排序的思路和插入排序非常相似,也分已排序和未排序区间。但选择排序每次会从未排序区间中找到最小的元素,将其放到已排序区间的末尾。但是不像插入排序会移动数组 选择排序会每次进行交换,如以下例子:     

4 5 6 3 2 1

第一次:    1 5 6 3 2 4

第二次:    1 2 6 3 5 4

1.时间复杂度:O(N^2)

2.空间复杂度:O(n)

3.交换次数

4.稳定性:不稳定

   二:冒泡排序

        核心思路:冒泡排序只会操作相邻的两个数据。每次冒泡操作都会对相邻的两个元素进行比较,看是否满足大小关系要求。如果不满足就让它俩互换。一次冒泡会让至少一个元素移动到它应该在的位置,重复n次,就完成了n个数据的排序工作。

        举例说明:4 5 6 3 2 1,从小到大排序。 1 2 3 4 5 6

进行排序:什么样的情况下不做任何交换了呢,那就是所有的数都在它应该在的位置;O(n)

1.时间复杂度:O(n^2)

2.空间复杂度:O(n)

3.交换次数:挺大的

4.稳定性:稳定

package Sort2;

import java.util.Arrays;

/**
 * 冒泡排序
 */

public class BubbleSort {

	public static void main(String[] args) {

		int data[] = { 4, 5, 6, 3, 2, 1 };
		int n = data.length;

		//n-1:这里是因为判断两个数是只比较一次 例如: 1  2   比较次数只会比一次
		for (int i = 0; i < n - 1; i++) {	//排序的次数
			//优化:如果所有的数都排好了,不需要交换了,就不需要冒泡了,所以直接退出
			boolean flag = false;
			// n-1-i:要减掉i是因为每次冒泡排序都会将后面的值确定,所以i就是后面已经排好的数字,所以就不需要再比较了,所以得减掉
			for (int j = 0; j < n - 1 - i; j++) {	//具体冒泡 n - 1 - i,6,5,4,3,2,1
				if (data[j] > data[j + 1]) {
					//交换
					int temp = data[j];	//用了第三个变量,不用第三个变量
					data[j] = data[j + 1];
					data[j + 1] = temp;
					flag = true;

					//异或实现
//					data[j] = data[j] ^ data[j+1];
//					data[j+1] = data[j] ^ data[j+1];
//					data[j] = data[j] ^ data[j+1];
				}
			}
			if(!flag) break;
		}
		System.out.println(Arrays.toString(data));
	}
}
/**
 * 下面是交换的时候如果不用第三方变量存储的话如何交换
 */
// a:2 b:3
// 3 2 => a:3 b:2
// 用加减
//a = a + b => a = 3+2 =5;
//b = a - b => b = 5-3 =2;
//a = a - b => a = 5-2 =3;
   2.1 如何进行简单的优化:

                1.  在交换的时候会需要第三方变量,会占空间,所以可以用异或交换。

                2. 当排好序了就不需要继续循环了,所以加flag作为标签。

       2.2 如何实现异或交换?

        异或操作可以实现交换两个数字的值的原因是因为异或操作具有以下几个性质:

  1. 任何数和0异或的结果仍然是这个数本身:a ^ 0 = a
  2. 任何数和自身异或的结果是0:a ^ a = 0
  3. 异或操作满足交换律:a ^ b = b ^ a 利用这些性质,我们可以通过异或操作实现交换两个数字的值,具体步骤如下: 假设有两个变量a和b,它们的初始值分别为a0和b0。
  4. 第一步:通过将a与b异或,将结果保存在a中:a = a ^ b。 此时,a的值为a0 ^ b0,b的值保持不变。
  5. 第二步:再将a与b异或,将结果保存在b中:b = a ^ b。 在这一步中,我们可以将上一步得到的a的值(a0 ^ b0)再与b0异或,得到的结果就是a0,即原始的a的值。 同时,由于异或操作满足交换律,所以b = (a0 ^ b0) ^ b0 = a0 ^ (b0 ^ b0) = a0 ^ 0 = a0。 此时,a的值保持不变,b的值变为a0。
  6. 第三步:最后将a与b异或,将结果保存在a中:a = a ^ b。 在这一步中,我们将上一步得到的a的值a0 ^ b0与上一步得到的b的值(a0)异或,得到的结果就是b0。
public class SwapNumbers {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        
        System.out.println("交换前:");
        System.out.println("a = " + a);
        System.out.println("b = " + b);
        
        // 使用异或操作交换a和b的值
        a = a ^ b;
        b = a ^ b;
        a = a ^ b;
        
        System.out.println("交换后:");
        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
}

        三: 快速排序

45 28 80 90 50 16 100 10

基准数:一般就是取要排序序列的第一个。

第一次排序基准数:45

从后面往前找到比基准数小的数进行对换: 10 28 80 90 50 16 100 45

从前面往后面找比基准数大的进行对换: 10 28 45 90 50 16 100 80    

   10 28 16 90 50 45 100 80  

   10 28 16 45 50 90 100 80

以基准数分为3部分,左边的比之小,右边比之大:

{10 28 16} 45 {50 90 100 80}

到此第一次以45位基准数的排序完成。

1.时间复杂度:nlogn 最坏的情况就是O(n^2)

2.空间复杂度:O(n)

3.稳定性:不稳定

4.快排和归并的对比:

(1)归并排序的处理过程是由下到上的,先处理子问题,然后再合并。

(2)快排其实就是从上到下,先分区,在处理子问题,不用合并。 其优化就是优化基准数,提供一个取三个数中间的思路.

package Sort2;

public class QuiklySort {

	public static void qSort(int data[], int left, int right) {

		int base = data[left]; // 就是我们的基准数,取序列的第一个,不能用data[0]
		int ll = left; // 表示的是从左边找的位置
		int rr = right; // 表示从右边开始找的位置
		while (ll < rr) {
			// 从后面往前找比基准数小的数
			while (ll < rr && data[rr] >= base) {
				rr--;
			}
			//这里有个小技巧,如果ll < rr为true,说明 data[rr] >= base = false,就找到比基准数小的,就要交换
			if (ll < rr) { // 表示是找到有比之大的
				int temp = data[rr];
				data[rr] = data[ll];
				data[ll] = temp;
				ll++;
			}
			// 从前面往后找比基准数大的数
			while (ll < rr && data[ll] <= base) {
				ll++;
			}
			if (ll < rr) {
				int temp = data[rr];
				data[rr] = data[ll];
				data[ll] = temp;
				rr--;
			}
		}
		// 肯定是递归 分成了三部分,左右继续快排,注意要加条件不然递归就栈溢出了
		//ll:循环终止时为基准数在最中间,然后将ll左右两部分继续递归
		if (left < ll)
			qSort(data, left, ll - 1);
		if (ll < right)
			qSort(data, ll + 1, right);

	}
}

        各种排序比较:

这么多种排序算法我们究竟应该怎么选择呢?

1.分析场景:稳定还是不稳定

2.数据量:数据量小的时候选什么?比如就50个数,优先选插入(5000*5000=25000000)

3.分析空间: 综上所述,没有一个固定的排序算法,都是要根据情况分析的。但是如果你不会分析的情况下 选择归并或者快排。

        四:计数排序

        如何对一个省200万学生的高考成绩(假设成绩最多只有2位小数,0~900范围)进行排序,用尽可能高效的算法。

package sorttest;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;

/**
 * 如何对一个省200万学生的高考成绩(假设成绩最多只有2位小数,0~900范围)进行排序,用尽可能高效的算法。
 *	计数排序
 */

public class CountSort {
	public static void main(String[] args) throws Exception {
		String str = null;
		String fileName = "D:\\JavaCode\\tulin\\src\\sorttest\\200w.txt";
		InputStreamReader isr = new InputStreamReader(new FileInputStream(fileName), "UTF-8");
		BufferedReader br = new BufferedReader(isr);
		int data[] = new int[2100002];
		int i = 0;
		//遍历所有的数据存到数组中
		while ((str = br.readLine()) != null) {
			double a = Double.valueOf(str);
			a = a * 100;
			data[i++] = (int) a;
			// System.out.println((int) a);
		}
		System.out.println("开始值为" + i);
		long start = System.currentTimeMillis();
		countSort(data, 0, data.length - 1);
		System.out.println("结束时间为" + (System.currentTimeMillis() - start) + "ms");
	}

	public static void countSort(int data[], int min, int max) throws Exception {
		int counts[] = new int[max + 1];
		//将所存的数字按照数组下标存储计数,
		for (int i = 0; i < data.length; i++) {
			counts[data[i]]++;
		}

		File file = new File("D:\\JavaCode\\tulin\\src\\sorttest\\200w-csort.txt");
		Writer out = new FileWriter(file);

		//同时从0开始遍历,所以也默认排好序,直接输出
		for (int i = 0; i <= max; i++) {
			if (counts[i] > 0) {
				for (int j = 0; j < counts[i]; j++) {
					out.write(((double) (i / 100.0)) + "\r\n");
				}
			}
		}
		out.close();
	}
}

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

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

相关文章

SetWindowDisplayAffinity 函数设置窗体透明

#define WDA_NONE 0x00000000 #define WDA_MONITOR 0x00000001 #define WDA_EXCLUDEFROMCAPTURE 0x00000011 c#调用示例 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.L…

从金融史、司法体系与技术周期来看,RWA的万亿叙事经不起推敲?

加密市场走向低迷&#xff0c;但RWA&#xff08;Real World Assets&#xff0c;真实世界资产&#xff09;概念却不断升温&#xff0c;成为这个行业里为数不多各方都承认的宏大叙述&#xff0c;吸引了高盛、花旗等传统机构的兴趣。不过从金融史、司法体系与区块链技术周期等方面…

Linux基本指令及其使用

前言&#xff1a;前面我们学习了Linux环境的简单配置和XShell7的安装&#xff0c;并将云服务器部署连接到XShell本地来使用&#xff0c;今天&#xff0c;我们就一起来学习一些Linux的基本指令及其使用&#xff0c;为后续的Linux的学习打基础&#xff0c;下面&#xff0c;马上开…

openGauss学习笔记-64 openGauss 数据库管理-创建和管理表空间

文章目录 openGauss学习笔记-64 openGauss 数据库管理-创建和管理表空间64.1 背景信息64.2 注意事项64.3 操作步骤64.3.1 创建表空间64.3.2 在表空间中创建对象64.3.3 查询表空间64.3.4 查询表空间使用率64.3.5 修改表空间64.3.6 删除表空间 openGauss学习笔记-64 openGauss 数…

vite+vue3项目中集成ESLint与prettier

1. 集成eslint 1.1 安装eslint npm add -D eslint1.2 初始化ESLint配置 npx eslint --init1.3 配置初始化选择 我的选择如下&#xff1a; 安装完成后&#xff08;根目录会生成.eslintrc.js文件&#xff09; 这个配置文件是默认生成的 1.4 eslint不生效解决方案 检查vscode…

DEFORMABLE DETR: DEFORMABLE TRANSFORMERS FOR END-TO-END OBJECT DETECTION (论文解析)

DEFORMABLE DETR: DEFORMABLE TRANSFORMERS FOR END-TO-END OBJECT DETECTION 摘要1 介绍2 相关工作3 重新审视 Transformers 和 DETR4 方法4.1 用于端到端目标检测的可变形transformer4.2 Deformable Detr的其他改进和变型5 实验5.1 和DETR 比较5.2 消融实验5.3 与最先进方法的…

python数据分析之Pandas库(一)

Pandas介绍 Pandas有两种常用的数据结构&#xff1a; Series &#xff08;一维数据&#xff09;与 DataFrame&#xff08;二维数据&#xff09;。 Series 是一种类似于一维数组的对象&#xff0c;能保存不同数据类型。 DataFrame 是一个二维的表格型的数据结构。 一、导入 i…

网络编程(一):服务器模型、Java I/O模型、Reactor事件处理模型、I/O复用

文章目录 一、Socket和TCP/IP协议族的关系二、服务器模型1.C/S模型&#xff08;Client/Server Model&#xff09;2.P2P模型&#xff08;Peer-to-Peer Model&#xff09; 三、Java的I/O演进1.BIO&#xff08;阻塞&#xff09;&#xff08;1&#xff09;工作流程&#xff08;2&am…

MATLAB实现函数拟合

目录 一.理论知识 1.拟合与插值的区别 2.几何意义 3.误差分析 二.操作实现 1.数据准备 2.使用cftool——拟合工具箱 三.函数拟合典例 四.代码扩展 一.理论知识 1.拟合与插值的区别 通俗的说&#xff0c;插值的本质是根据现有离散点的信息创建出更多的离散点&#xf…

HashMap解决哈希冲突

要了解 Hash冲突&#xff0c;那首先我们要先了解 Hash 算法和 Hash 表。 Hash算法 Hash 算法&#xff0c;就是把任意长度的输入&#xff0c;通过散列算法&#xff0c;变成固定长度的输出&#xff0c;这个输出结果是散列值。 Hash表 Hash 表又叫做“散列表”&#xff0c;它是通…

7.Xaml Image控件

1.运行图片 2.运行源码 a.xaml源码 <!--Source="/th.gif" 图像源--><!--Stretch="Fill" 填充模式--><Image x:Name

Qemu 架构 硬件模拟器

Qemu 架构 硬件模拟器 Qemu 是纯软件实现的虚拟化模拟器&#xff0c; 几乎可以模拟任何硬件设备&#xff0c; 我们最熟悉的就是能够模拟一台能够独立运行操作系统的虚拟机&#xff0c; 虚拟机认为自己和硬件打交道&#xff0c; 但其实是和 Qemu 模拟出来的硬件打交道&#xff…

单元测试界的高富帅,Pytest框架 (二) 前后置方法和 fixture 机制

前言 上一篇文章入门篇咱们介绍了pytest的基本使用&#xff0c;这一篇文章专门给大家讲解pytest中关于用例执行的前后置步骤处理,pytest中用例执行的前后置处理既可以通过测试夹具(fixtrue)来实现&#xff0c;也可以通过xunit 风格的前后置方法来实现。接下来我们一起看看如何…

利用procrank和lsof定位出客户软件内存OOM的问题

最近遇到一些事情&#xff0c;觉得挺憋屈的&#xff0c;可是再憋屈总得往前走吧&#xff01;打工人&#xff0c;不好办啊&#xff01;事情是这样的&#xff0c;笔者在芯片原厂负责SDK和行业解决方案输出的&#xff0c;可以理解成整体SDK turnkey方案。但是有些客户多少还要改一…

单例模式(饿汉式单例 VS 懒汉式单例)

所谓的单例模式就是保证某个类在程序中只有一个对象 一、如何控制只产生一个对象&#xff1f; 1.构造方法私有化&#xff08;保证对象的产生个数&#xff09; 创建类的对象&#xff0c;要通过构造方法产生对象 构造方法若是public权限&#xff0c;对于类的外部&#xff0c;可…

企业架构LNMP学习笔记31

负载均衡服务器的高可用备用服务器配置&#xff1a; 负载均衡服务器的配置比单台服务器的配置要高很多。硬件上要上一个台阶。 所有的请求流量都要经过负载均衡服务器&#xff0c;负载均衡服务器压力很大&#xff0c;防止她宕机&#xff0c;导致后端web服务器都不可用&#xf…

ROS2下使用TurtleBot3-->SLAM导航(仿真)RVIZ加载不出机器人模型

一、问题描述 在使用台式机进行仿真时&#xff0c;大部分例程很顺利&#xff0c;但在SLAM导航时&#xff0c;在RVIZ中却一直加载不出机器人模型&#xff0c;点击Navigation2 Goal选择目标点进行导航时&#xff0c;无响应。 启动后在RVIZ2和终端看到一个错误 按照官网的指令试…

探索 Wall-E 的寻路算法

几年前,Yandex 组织了一场名为“机器人快递员”的竞赛,并提供了诱人的奖品:一张参加专业人士封闭式自动驾驶会议的门票。该竞赛类似于一场游戏,参与者的任务是在地图上找到最佳路线并使用机器人快递员优化送货。 当我深入研究这个主题时,我发现尽管路线查找问题已经解决,…

ms17-010(永恒之蓝)漏洞复现

目录 前言 一、了解渗透测试流程 二、使用nmap工具对win7进行扫描 2.1 2.2 2.3 2.4 2.5 三、尝试ms17-010漏洞利用 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 四、结果展示 4.1 4.2 4.3 4.4 4.5 总结 前言 ms17-010&#xff08;永恒之蓝&am…

mysql八股1

参考MySQL八股文连环45问&#xff08;背诵版&#xff09; - 知乎 (zhihu.com) 基础 1.范式 第一范式&#xff1a;强调的是列的原子性 第二范式&#xff1a;要求实体的属性完全依赖于主关键字。所谓完全 依赖是指不能存在仅依赖主关键字一部分的属性。&#xff08;就是主键不…