交换排序(冒泡/快排)

一 . 交换排序

交换排序基本思想 : 

所谓交换 , 就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置 。

交换序列的特点是 : 将键值较大的记录向序列的尾部移动 , 键值较小的记录向序列的前部移动

 

 1.1 冒泡排序

在前面中 , 介绍了冒泡排序的思路了 冒泡排序是一种最基础的交换排序 。 之所以叫做冒泡排序 , 因为每个元素都可以像小气泡一样 , 根据自身大小一点一点移动到对应的位置 。其本质就是两两数值进行比较 。 

//冒泡排序
void BubbleSort(int* arr, int n)
{
	//比较的趟数
	for (int i = 0; i < n-1; i++)
	{
		int exchange = 0;
		//一趟中比较的次数
		for (int j = 0; j < n - i - 1; j++) {
			if (arr[j] > arr[j + 1])
			{
				Swap(&arr[j], &arr[j + 1]);
				exchange = 1;
			}
		}
		if (exchange == 0)
		{
			break;
		}
	}
}

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

空间复杂度 : O ( 1 ) 

1.2 快速排序

快速排序是Hoare 于1962 年提出的一种  二叉树  的交换排序方法 ,  其基本思想为 : 任取待排序元素中的某元素作为基准值 , 按照该排序码 将待排序集合分割成  两个子序列左子序列中所有元素均小于基准值 右子序列中 所有元素均大于基准值 , 然后左右子序列重复该过程 , 直到所有元素都排列到相应的位置上 。

 快速排序实现的主框架 : 

//快速排序
void QuickSort(int* arr, int left, int right)
{
	if (left >= right)
	{
		return;
	}
	//找基准值
	int keyi = _QuickSort(arr, left, right);

	//二分查找
	// [0 , keyi -1 ]      keyi     [ keyi + 1 , right]
	QuickSort(arr, 0, keyi - 1);
	QuickSort(arr, keyi + 1 ,right);
}

将区域中的元素进行划分的   _QuickSort方法  主要有以下几种实现方式 :  

 

1.2.1 Hoare 版本

基本思路 :

1 ) 创建左右指针 , 以确定基准值

2 ) 左指针从左往右找比 基准值要大的数据, 右指针从右往左找比基准值要小的数据 , 然后左右指针数据交换 , 继续循环 , 直到 左指针的下标值比右指针的 大

3 )当 左指针的下标值比右指针的大时 , 基准值 与 右指针的数值交换

例如 对数组 a [ ] = { 6 , 1 , 2 , 7 , 9 , 3 } 进行快速排序  : 

 

  •  问题 一 : 为什么跳出循环后right 位置的值一定不大于 key ?

因为在 left > right 时 , right 走到了 left 的左侧 , 而再次之前 left 已经把最大的值找到并且与 right 交换 ( left 扫描过的数据均不大于key ) ;

相遇点的值有三种情况 : 

 

  •  问题 二 : 为什么 left 和 right 指定的数据和 key 值相等时候也交换 ? (也就是以下代码加个 "  =  " 为啥不行 )

相等的值参与交换确实会有一定额外的消耗 。 实际还有各种复杂的场景 ,假设数组中的数据大量重复的时候 无法进行有效的分割排序 !时间复杂度会变高 !

 时间复杂度分析 :

递归算法的时间复杂度的计算 : 递归次数 * 单次递归的时间复杂度

                                                      \log_{2}n    *       n

快速排序的时间复杂度为 : O(n*logn )

如果数组为有序 : 快排的时间复杂度为 O(n^2)

1.2.2 挖坑法

思路 : 

创建左右指针 。 首先从右向左找出比基准小的数据 , 找到后立即放入到左边坑中 , 当前位置变为新  “坑” , 然后从左向右找出比基准大的数据 , 找到后立即放入到右边坑中 , 当前位置变为新的 “坑” , 结束循环后将最开始存储的分界值放入到当前的 "坑“ 中 , 返回当前 ” 坑“ 下标(即分界值的下标)

//挖坑法
int _QuickSort1(int* arr, int left, int right)
{
	int key = arr[left];
	int hole = left;
	while (left < right)
	{
		while (left < right && arr[right] > key)
		{
			right--;
		}
		arr[hole] = arr[right];
		hole = right;
		while (left < right && arr[left] < key)
		{
			left++;
		}
		arr[hole] = arr[left];
		hole = left;
	}
	arr[hole] = key;
	return hole;
}

 

1.2.3 lomuto指针

创建前后指针 , 从左往右找比  基准值小  的进行交换 , 使得小的都排在基准值的左边 。 

//双指针法
int _QuickSort2(int* arr, int left, int right)
{
	int prev = left, cur = prev + 1;
	int key = left;
	while (cur <= right)
	{
		if (arr[cur] < arr[key] && ++prev !=cur)
		{
			Swap(&arr[prev], &arr[cur]);
		}
		cur++;
	}
	Swap(&arr[prev], &arr[key]);
	return prev;
}

快速排序特性总结 :

1 . 时间复杂度 : O(n * logn)

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

 1.2.4 非递归版本

非递归版本的快速排序需要借助数据结构 : 栈

void QuickSortNonR(int* arr, int left, int right)
{
	ST st;
	STInit(&st);
	StackPush(&st, right);
	StackPush(&st, left);
	while (!StackEmpty(&st))
	{
		//取栈顶元素——两次
		int begin = STTop(&st);
		StackPop(&st);

		int end = STTop(&st);
		StackPop(&st);

		//对区间[begin,end]找基准值---双指针法
		int prev = begin, cur = prev + 1;
		int keyi = begin;
		while (cur <= end)
		{
			if (arr[cur] < arr[keyi] && ++prev != cur)
			{
				Swap(&arr[prev], &arr[cur]);
			}
			++cur;
		}
		Swap(&arr[keyi], &arr[prev]);
		keyi = prev;
		//此时基准值的下标:keyi
		//划分左右序列:[begin,keyi-1] [keyi+1,end]
		if (keyi + 1 < end)
		{
			StackPush(&st, end);
			StackPush(&st, keyi + 1);
		}

		if (keyi - 1 > begin)
		{
			StackPush(&st, keyi - 1);
			StackPush(&st, begin);
		}
	}

	STDestory(&st);
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【反射率】-- Lab 转换(excel)

系列文章目录 文章目录 系列文章目录前言一、CIE1.CIE 简介2.cie 1931标准色度匹配函数数据3.从CIE1931RGB到CIE1931 XYZ 二、Lab颜色空间的理解1.Lab色差公式怎么计算色差 三、D65光源Lab计算总结 前言 一、CIE 1.CIE 简介 CIE是由国际照明工程领域中光源制造、照明设计和光…

[ 问题解决篇 ] win11中本地组策略编辑器gpedit.msc打不开(gpedit.msc缺失)

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

c语言素数优化,图解

方法① 2~m-1范围 整体思路就是&#xff0c;整数取余0就break&#xff0c;后续判断取余不为0的i次数&#xff0c;如果到头也就是i值溢出m-1 也就是最后一次循环i都没break&#xff0c;说明全部取余都不为0&#xff0c;贼为素数 尽头 i<m-1 等于号和-1可以抵消&#xff0c; …

跨境电商行业中的主数据有哪些?

在全球化和数字化的推动下&#xff0c;跨境电商行业正迎来前所未有的发展机遇。无论是品牌拓展国际市场还是小型卖家进入全球电商平台&#xff0c;跨境电商企业都需要面对海量数据的管理与整合。在这个行业中&#xff0c;主数据管理尤为重要&#xff0c;因为跨境电商涉及到复杂…

opencv - py_imgproc - py_grabcut GrabCut 算法提取前景

文章目录 使用 GrabCut 算法进行交互式前景提取目标理论演示 使用 GrabCut 算法进行交互式前景提取 目标 在本章中 我们将了解 GrabCut 算法如何提取图像中的前景我们将为此创建一个交互式应用程序。 理论 GrabCut 算法由英国剑桥微软研究院的 Carsten Rother、Vladimir K…

Android编译环境构建(二)(可用于物理机、虚拟机、容器化Jenkins环境)

文章目录 需求环境要求文件下载Gradle Version:7.5cmdline-tools至此普通物理环境的Android编译环境已部署完毕 部署maven(可选)Jenkins配置Android构建环境 说明&#xff1a; 物理环境&#xff1a;物理机、虚拟机等 容器化环境&#xff1a;docker等 需求 Gradle Version:7.5 …

Django安装

在终端创建django项目 1.查看自己的python版本 输入对应自己本机python的版本&#xff0c;列如我的是3.11.8 先再全局安装django依赖包 2.在控制窗口输入安装命令&#xff1a; pip3.11 install django 看到Successflully 说明我们就安装成功了 python的Scripts文件用于存…

【免费】跟网型逆变器小干扰稳定性分析与控制策略优化

目录 主要内容 模型研究 数学模型 2.小信号控制结构 3.仿真模型 结果一览 下载链接 主要内容 弱电网往往具有阻抗较大和短路比较小等特点&#xff0c;易导致系统不稳定&#xff0c;限制了功率传输能力。该仿真建立了弱电网下跟网型逆变器的小信号扰动状态空间模…

aws(学习笔记第十课) 对AWS的EBS如何备份(snapshot)以及使用snapshot恢复数据,AWS实例存储

aws(学习笔记第十课) 对AWS的EBS如何备份&#xff08;snapshot&#xff09;以及使用snapshot&#xff0c;AWS实例存储 学习内容&#xff1a; 对AWS的EBS如何备份AWS实例存储EBS和实例存储的不足 1. 对AWS的EBS如何备份&#xff08;snapshot&#xff09;以及使用snapshot恢复数…

开源 AI 智能名片 2 + 1 链动模式 S2B2C 商城小程序中积分使用价值的拓展策略

摘要&#xff1a;本文围绕开源 AI 智能名片 2 1 链动模式 S2B2C 商城小程序&#xff0c;深入探讨其积分使用价值的丰富策略。详细分析积分兑换礼品、会员升级、积分抵现等方式在该特定商城小程序环境下的应用特点、存在问题及对用户和商城的影响&#xff0c;旨在为商城的优化运…

async函数和await表达式

async函数 函数的返回值为promise对象 promise对象的结果由async函数执行的返回值决定 async函数的返回值 和then方法的返回值以及返回类型的判断办法一致 如果返回值是一个非promise类型的数据 返回的promise的类型为fulfilled或者resolved 如果返回的是一个promise对象 …

软件测试--BUG篇

博主主页: 码农派大星. 数据结构专栏:Java数据结构 数据库专栏:MySQL数据库 JavaEE专栏:JavaEE 软件测试专栏:软件测试 关注博主带你了解更多知识 目录 1. 软件测试的⽣命周期 2. BUG 1. BUG 的概念 2. 描述bug的要素 3.bug级别 4.bug的⽣命周期 5 与开发产⽣争执怎…

Linux云计算 |【第五阶段】CLOUD-DAY8

主要内容&#xff1a; 掌握DaemonSet控制器、污点策略&#xff08;NoSchedule、Noexecute&#xff09;、Job / CronJob资源对象、掌握Service服务、服务名解析CluterIP&#xff08;服务名自动发现&#xff09;、&#xff08;Nodeport、Headless&#xff09;、Ingress控制器 一…

基于java+SpringBoot+Vue的新闻推荐系统设计与实现

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis Maven mysql5.7或8.0等等组成&#x…

我主编的电子技术实验手册(22)——RC并联电路

本专栏是笔者主编教材&#xff08;图0所示&#xff09;的电子版&#xff0c;依托简易的元器件和仪表安排了30多个实验&#xff0c;主要面向经费不太充足的中高职院校。每个实验都安排了必不可少的【预习知识】&#xff0c;精心设计的【实验步骤】&#xff0c;全面丰富的【思考习…

设备树基本语法

文章目录 设备树基本语法跟节点子节点reg属性address-cells 和 size-cells 属性model 属性status 属性compatible 属性aliases 节点chosen 节点device_type 节点自定义属性 当描述设备树&#xff08;Device Tree&#xff09; 时&#xff0c; 通常会涉及到以下几个关键术语&…

【环境搭建】Apache Kylin 各个版本Docker搭建汇总

前言 最近需要做一些Web漏洞复现的研究&#xff0c;所以需要搭建不同版本的Apache Kylin&#xff0c;在这里汇总一下。 用Docker来搭建环境是最简单的方式&#xff0c;因为无需在本地构建镜像&#xff0c;只需执行以下命令直接从 Docker Hub 拉取镜像&#xff0c;当容器启动时…

linux操作系统进程

linux操作系统是对下的软硬件进行管理&#xff0c;为了能够对上提供稳定&#xff0c;快速&#xff0c;安全的服务而诞生的软件。 广义上的操作系统是包含搭载在操作系统上的软件和函数库等文件的。 狭义上的操作系统就是操作系统内核&#xff0c;进行进程管理&#xff0c;文件…

CentOS9 Stream 支持输入中文

CentOS9 Stream 支持输入中文 方法一&#xff1a;确保 gnome-control-center 和相关组件已更新方法二&#xff1a;手动添加输入法源配置方法三&#xff1a;配置 .xinputrc 文件方法四&#xff1a;检查语言包 进入centos9 stream后&#xff0c;点击右上角电源键&#xff0c;点击…

Linux权限管理和文件属性

目录 1. 权限的概念 2. 权限管理 2.1 文件访问者的分类 2.2 文件类型和访问权限&#xff08;事物属性&#xff09; 2.2.1 文件类型 2.2.2 file指令 2.2.3 基本权限 3. 文件访问权限的相关设置方法 3.1 chmod 3.2 chown 和 chgrp 3.3 umask 4. 粘滞位 1. 权限的…