【算法突击】排序算法系列(一) | 程序员面试 | 冒泡排序 | 快速排序 | 归并排序

news2024/11/25 23:13:12

【排序算法】 冒泡排序 | 快速排序 | 归并排序

文章目录

  • 【排序算法】 冒泡排序 | 快速排序 | 归并排序
  • 1. 冒泡排序
    • 1.1 核心思想
    • 1.2 代码实现
  • 2. 快速排序
    • 2.1 核心思想
    • 2.2 时间复杂度
    • 2.2 代码实现
  • 3. 归并排序
    • 3.1 核心思想
    • 3.2 时间复杂度
    • 3.3 代码实现

1. 冒泡排序

1.1 核心思想

将整个数组的排序问题,转化成“查找当前数组最大元素”的问题

  • 比较数组中相邻元素的大小,调整顺序,保证较大的元素在较小元素后面;
  • 重复上一步的比较,直到当前数组的最后一位停止;
  • 已找出的最大元素不参与下一轮比较,继续重复上述两个步骤,直到不再发生交换;

以nums = [49,38,65,97,76,13,27]为例,下面看看每一轮比较的结果:
在这里插入图片描述

1)第一轮比较

nums[0]与nums[1]比较,需要交换顺序;
在这里插入图片描述

nums[1]和nums[2]比较,不变;
在这里插入图片描述

nums[2]和nums[3]比较,不变;
在这里插入图片描述

nums[3]和nums[4]比较,交换顺序;
在这里插入图片描述

nums[4]和nums[5]比较,交换顺序;
在这里插入图片描述

nums[5]和nums[6]比较,交换顺序,此时的元素97就是当前数组中最大的元素;
在这里插入图片描述

2)第二轮比较

直接看最后一轮的比较结果,nums[4]和nums[5];
在这里插入图片描述

3)第三轮比较

直接看最后一轮的比较结果,nums[3]和nums[4];
在这里插入图片描述

4)第四轮比较

直接看最后一轮的比较结果,nums[2]和nums[3];
在这里插入图片描述

5)第五轮比较

直接看最后一轮的比较结果,nums[1]和nums[2];
在这里插入图片描述

6)第六轮比较

此时当前数组只剩两个元素,nums[0]和nums[1],比较过程中,没有发生元素交换,因此可以判定数组已经全部排序完成;
在这里插入图片描述

基于上述过程可以看出,我们除了要控制比较的轮次之外,还需要在每次比较中去遍历当前的子数组,对相邻元素进行比较,才能找到当前子数组中最大的元素。因此冒泡排序的时间复杂度是O(n^2)

1.2 代码实现

	public int[] sortArray(int[] nums) {
		// 比较的轮次
  	for (int i=0; i<nums.length; i++) {	
			// 相邻元素比较,较大元素后移
			boolean falg = false; // 当前比较轮次中是否发生了元素间的交换
  		for(int j=0; j< nums.length - i - 1; j++) {	
  			if(nums[j] > nums[j+1]) {
  				int tmp = nums[j];
  				nums[j] = nums[j+1];
  				nums[j+1] = tmp;
					flag = true;
  			}
  		}
			// 当前比较的轮次未发生元素交换,则代表数组已经全部排序完毕,可直接返回
			if(!flag){
				return nums;
			}
  	}
  	return nums;
  }

2. 快速排序

2.1 核心思想

将数组的排序问题,转化为“数组区间划分”问题:

  • 选中的数组nums中的元素num作为基准元素;
  • 重新划分当前数组的区间,使得num左边的所有元素(如果有)都小于num,num右边的所有元素(如果有)都大于num;
  • 递归地在nums的左右区间(如果有)中,重复上面两个步骤,直到区间只有一个元素时停止;

以nums = [49,38,65,97,76,13,27]为例,我们选取的元素num = nums[0] = 49,为了方便划分区间,同时为左右分区各设置了一个指针i和j,i的起始下标是0,j的起始下标是6;下面看看每一轮数组划分的结果:
在这里插入图片描述

1)第一轮区间划分(选中数组第一个元素49)

当i=0, j=6时,nums[6] < 49,nums[0] = 49,nums[6]应该划分到49的左边区间;
在这里插入图片描述

当i=1, j=6时,nums[1] < 49,符合预期,此时不做调整;
在这里插入图片描述

当i=2, j=6时,nums[2] > 49,nums[i]应该划分到49的右边区间;
在这里插入图片描述

当i=2, j=5时,nums[2] > 49,nums[i]应该划分到49的右边区间;
在这里插入图片描述

当i=3, j=5时,nums[3] > 49,nums[3]应该划分到49的右边区间;
在这里插入图片描述

当i=3, j=4时,nums[4] > 49,符合预期,此时不做调整;
在这里插入图片描述

当i=3, j=3时,此时区间划分完毕,直接将49这个元素填到nums[3]中;
在这里插入图片描述

2**)第二轮区间划分(元素49的左半区间,选择第一个元素27)**

当i=1, j=1时,此时区间划分完毕,直接将27这个元素填到nums[1]中;
在这里插入图片描述

3**)第三轮区间划分(元素49的右半区间,选择第一个元素76)**

当i=5, j=5时,此时区间划分完毕,直接将76这个元素填到nums[5]中;
在这里插入图片描述

至此,整个快速排序的过程就分析完了,其求解的目标是将数组划分成左右两个区间,并利用分治的思想不停的划分下去,直到划分的区间内只有一个元素才会停止。

2.2 时间复杂度

对于nums = [49,38,65,97,76,13,27]这个输入,快速排序的的计算过程就像是一棵二叉树
在这里插入图片描述

他的计算规模可以抽象地用一颗完全二叉树表示,该树总共有n个节点(n为输入数组的长度),其节点内的值表示当前层次中需要遍历的元素数量。
在这里插入图片描述

所以,快速排序的时间复杂度应该是树中节点总数 * 树的高度,即O(nlogn)

2.2 代码实现

	public int[] sortArray2(int[] nums) {
		quickSort(nums, 0, nums.length - 1);
		return nums;
	}

	private void quickSort(int[] nums, int start, int end) {
		if (start >= end) {
			return;
		}
		
		int i = start;
		int j = end;
		int tmp = nums[i];
		// 将nums[i]为基准划分区间,并且保证其左边元素都小于nums[i],右边元素都大于nums[i]
		while (i < j) {
			while (nums[j] >= tmp && i < j) {
				j--;
			}
			nums[i] = nums[j];
			while (nums[i] <= tmp && i < j) {
				i++;
			}
			nums[j] = nums[i];
		}
		nums[i] = tmp;

		// 分治递归左右两区间
		quickSort(nums, start, i - 1);
		quickSort(nums, i + 1, end);
	}

3. 归并排序

3.1 核心思想

将整个数组的排序问题,转换成了“子数组切分”和“两个有序子数组合并”的的问题

  • 递归地将数组切分成多个子数组,直到长度为1时停止;
  • 递归地对有序的子数组,进行两两合并,直到还原成原数组的长度;
    以nums = [49,38,65,97,76,13,27]为例,设置指针i,j分别表示当前切分的子数组的起始下标和结束下标,下面看看每一轮数组“切分-合并”的结果:
    在这里插入图片描述

1)左半数组nums[0:3]

切分:i=0, j=3
在这里插入图片描述

切分:i=0, j=1
在这里插入图片描述

切分:i=0, j=0
在这里插入图片描述

合并:i=0, j=1,nums[0] > nums[1],需要交换位置
在这里插入图片描述

切分:i=2, j=2
在这里插入图片描述

合并:i=2, j=3,此时nums[2] < nums[3],不需要改动
在这里插入图片描述

合并:i=0, j=3,至此左半区间就合并完成了
在这里插入图片描述

2)右半数组nums[4:6]

i=4,j=6
在这里插入图片描述

3**)整个nums数组**

i=0,j=6
在这里插入图片描述

3.2 时间复杂度

对于nums = [49,38,65,97,76,13,27]这个输入的计算过程如下图所示:
在这里插入图片描述

消耗时间的元素便利过程都集中在“合并”的过程中,可以将合并的过程看作是一颗**完全二叉树,**该树总共有n个节点(n为输入数组的长度),其节点内的值表示当前层次中需要遍历的元素数量。
在这里插入图片描述

所以,归并排序的时间复杂度是树中节点总数 * 树的高度,即O(nlogn)

3.3 代码实现

	public int[] sortArray3(int[] nums) {
		mergeSort(nums, 0, nums.length - 1);
		return nums;
	}

	private void mergeSort(int[] nums, int start, int end) {
		if (start >= end) {
			return;
		}
		int middle = (start + end) / 2;
		mergeSort(nums, start, middle);
		mergeSort(nums, middle + 1, end);
		merge(nums, start, middle, end);
	}

	// 调整区间[start, end有序]有序,其中[start, middle],[middle+1, end]区间已经有序
	private void merge(int[] nums, int start, int middle, int end) {
		int i = start; // 左半数组的起始下标
		int j = middle + 1; // 右半数组的起始下标

		int[] tmp = new int[end + 1]; // 暂存有序的nums数组
		int k = 0;
		while (i <= middle && j <= end) {
			if (nums[i] < nums[j]) {
				tmp[k++] = nums[i++];
			} else {
				tmp[k++] = nums[j++];
			}
		}
		// 如果还有一边的数组有多余元素,则直接复制到tmp中
		while (i <= middle) {
			tmp[k++] = nums[i++];
		}
		while (j <= end) {
			tmp[k++] = nums[j++];
		}
		// copy回原数组nums
		for (k = 0, i = start; i <= end; i++, k++) {
			nums[i] = tmp[k];
		}
	}

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

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

相关文章

【接口自动化】接口间参数传递的一种解决方案

本文转载自&#xff1a;接口间参数传递的一种解决方案 做过接口自动化测试的同学肯定都熟悉在全链路测试过程中&#xff0c;很多业务场景的完成并非由单一接口实现&#xff0c;而是由很多接口组成的一条链路实现。例如你在淘宝上购物场景。 不同于单接口测试&#xff0c;这种链…

2 线性模型

文章目录一般流程问题引入数据集与测试集过拟合与泛化开发集监督学习和非监督学习问题分析训练集、验证集、测试集模型设计模拟训练过程课程代码课后习题代码课程来源&#xff1a; 链接文档参考&#xff1a; 链接以及 BirandaのBlog&#xff01;一般流程 对于一般的线性模型来…

微信小程序 Springboot校园招聘求职系统

基于微信小程序的校园求职系统的设计基于现有的手机&#xff0c;可以实现首页、个人中心、岗位类型管理、用户管理、企业管理、招聘信息管理、应聘信息管理、系统管理等功能。方便用户对首页、招聘信息、我的等详细的了解及统计分析 一个基本的程序包含app.json、project.confi…

谈谈SpringBoot(二)

1. Spring Boot缓存 1.1 JSR-107 Spring从3.1开始定义了org.springframework.cache.Cache 和org.springframework.cache.CacheManager接口来统一不同的缓存技术&#xff1b; 并支持使用JCache&#xff08;JSR-107&#xff09;注解简化我们开发。 Cache接口为缓存的组件规范定义…

day23|93.复原IP地址、78.子集、90.子集II

93.复原IP地址 有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 . 分隔。 例如&#xff1a;"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址&#xff0c;但是 &q…

layui框架学习(2:颜色、图标、动画)

B站教学视频中对Layui的颜色没有专门介绍&#xff0c;而Layui官方教程中虽然有颜色章节&#xff0c;但也只是简单介绍了基色调、辅色调、中性的颜色的概念及用途&#xff0c;最后说明layui 内置了七种背景色&#xff0c;以便用于各种元素中&#xff0c;如&#xff1a;徽章、分割…

Go语言基础入门第二章

Go语言环境安装 下载地址&#xff1a;https://golang.google.cn/dl/ 下载完安装包直接安装即可&#xff0c;安装完毕后&#xff0c;打开cmd控制台&#xff0c;输入”go version“查看是否安装成功以及对应安装版本。 配置环境变量Go语言需要一个安装目录&#xff0c;还需要一个…

Spring Cloud_Eureka服务注册与发现

目录一、Eureka基础知识1.什么是服务治理2.什么是服务注册3.Eureka两组件二、单机Eureka构建步骤1.IDEA生成eurekaServer端服务注册中心2.服务提供者3.服务消费者代码链接 https://github.com/lidonglin-bit/cloud 一、Eureka基础知识 1.什么是服务治理 SpringCloud封装了Ne…

金融风控09

迁移学习 为什么要&#xff1f; 源域样本与目标域样本分布有区别&#xff0c;目标域样本量不够 平时建模用的迁移学习场景 1、新开某个消费分期场景样本量少&#xff0c;需要用其他场景的数据建模 2、业务被迫停滞3个月再重启&#xff0c;大部分训练样本比较老旧&#xff…

含分布式光伏的配电网集群划分和集群电压协调控制(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

激光在大气中传输特性

在光纤通信中&#xff0c;单模光纤在波长1.55μm窗口具有巨大的潜在带宽和极低的损耗&#xff0c;传输数字信号的容量已能达到10Tb&#xff0f;s&#xff0c;每信道光源功率仅需1mW左右&#xff0c;无中间放大的距离超过100km。而且&#xff0c;光纤作为光波导&#xff0c;红外…

PostSharp Ultimate添加模式和线程安全

PostSharp Ultimate添加模式和线程安全 PostSharpUltimate允许开发人员通过将重复的工作从人身上转移到机器上&#xff0c;从而消除样板代码。它包含最常见模式的现成实现&#xff0c;并为您提供了为自己的模式构建自动化的工具。开发人员通常根据设计模式进行思考&#xff0c;…

Go语言基础入门第一章

Go语言基础入门 Go语言的logo 为什么需要一个新的语言最近十年来&#xff0c;C/C在计算机领域得到了很好的发展&#xff0c;并没有新的系统编程语言出现。对开发程度和执行效率在很多情况下并不能兼得。要么是执行效率高&#xff0c;但是低效的开发和编译&#xff0c;如C&…

Redux Toolkit + React + Tailwind CSS 学习心得

Redux Toolkit React Tailwind CSS 学习心得 预览地址&#xff1a;https://goldenaarcher.com/movie-app-home-only&#xff0c;只实现了一个简单的首页功能&#xff0c;API 用的是 the Movie Database&#xff0c;不想用 API 的也可以装一个 faker-js/faker 用来随机生成伪…

学生护眼灯怎么选择?分享适合学生的护眼灯

现阶段的青少年与儿童的近视率非常高&#xff0c;选择一款好的台灯能够保证双眼的健康&#xff0c;首先先看亮度是否合理&#xff0c;不能刺眼&#xff0c;选择三基色灯管&#xff0c;光很柔和&#xff0c;看频闪&#xff0c;好的护眼台灯可以做到无可视频闪&#xff0c;是的视…

移动web适配和Less

移动web适配和Lessrem 适配rem 单位媒体查询flexible.js如何把设计稿的px转换为remLESSLess注释less 运算less 嵌套less 变量less导入less 导出控制当前Less文件导出less 禁止导出小结rem 适配 rem 单位 rem 是一个相对单位&#xff0c;1rem 就是 html 文字的大小 比如 /* …

Java基础10:常用API

Java基础10&#xff1a;常用API一、Math二、System1. currentTimeMillis2. arraycopy三、Runtime四、Object1. toString2. equals3. clone五、Objects六、BigInteger1. 构造方法&#xff08;获取BigInteger&#xff09;2. 常用方法七、BigDecimal1. 构造方法&#xff08;获取Bi…

计算机相关专业混体制的解决方案(考公务员)

文章目录序&#xff1a;编制介绍1、公务员报考要求2、公务员工作待遇3、公务员工作内容4、公务员报考复习序&#xff1a;编制介绍 编制介绍&#xff1a;编制&#xff0c;也就是常说的铁饭碗。 编制的诞生为了控制吃财政饭的人员数量无限膨胀而设置的&#xff0c;所以名额有限受…

密码学基本概念

密码学简介 密码是经过加密过后的口令&#xff0c;是指用特定的变换对数据信息进行加密保护或者安全身份认证的物质和技术&#xff0c;密码学是对安全通信技术的研究&#xff0c;要能够有效的防范潜在攻击&#xff0c;也就是对信息加密解密的过程。 密码基本性质 密码学的发展…

CSS3 选择器 :nth-child 与 :nth-of-type 区别

一、:nth-child 1.1 说明 :nth-child(n) 选择器匹配属于其父元素的第 N 个子元素&#xff0c;不论元素的类型。n 可以是数字、关键词或公式。 注意&#xff1a;如果第 N 个子元素与选择的元素类型不同则样式无效&#xff01; 1.2 示例 <style> div>p:nth-child(2…