排序 -- 冒泡排序和快速排序

一、 交换排序

1、基本思想

所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

2、常见的交换排序

1、冒泡排序

2、快速排序

二、冒泡排序

1、基本思想

从左到右,相邻元素进行比较。每次比较一轮,就会找到序列中最大或者最小的那一个数。这个数就会从序列的最右边冒出来。

以从小到大排序为例:第一轮比较后,所有的数中最大的那个数就会浮到最右边;第二轮比较后,所有数中第二大的数就会浮到倒数第二个位置上.......就这样一轮一轮地比较,最后实现从小到大排序。

2、冒泡排序的特性总结

  • 冒泡排序是一种非常容易理解的排序
  • 时间复杂度:O(N^2)
  • 空间复杂度:O(1)
  • 稳定性:稳定

 

3、冒泡排序

3.1、实现思想

 

3.2、具体实现

//冒泡排序
void BubbleSort(int* a, int n)
{
	for (int j = 0; j < n - 1; j++)
	{
		int exchange = 0;
		for (int i = 0; i < n - 1 - j; i++)
		{
			if (a[i] > a[i + 1])
			{
				Swap(&a[i], &a[i + 1]);
				exchange = 1;
			}
		}

		if (exchange == 0)
		{
			break;
		}
	}
}

三、快速排序

1、基本思想

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

 

 2、快速排序的特性总结

  • 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
  • 时间复杂度:O(N*logN)

  • 空间复杂度:O(logN)
  • 稳定性:不稳定

 

3、快速排序的不同版本

3.1 hoare版

分别定义两个下标 left 和 right,让他们一个从左往右开始遍历数组,另一个从右往左开始遍历数组,直到它们相遇后就结束遍历。在这个过程中,我们首先要定义一个基准值。为了方便就把left指向的值定为基准值。随后,在遍历数组的过程中如果下标 left 所指向的数大于基准值且下标 right 所指向的数小于基准值,那就互相交换数据。如果没有那两个下标就一直遍历数组直到相遇,两个下标相遇后,将基准值与此时在相遇位置的下标 left (right)的值进行交换,这样基准值就归位了。

int PartSort1(int* a, int left, int right)
{
	int keyi = left;

	while (left < right)
	{
		//keyi在左边,right先走
		//keyi在右边,left先走

		//找小
		while (left < right && a[right] >= a[keyi])
		{
			right--;
		}

		//找大
		while (left < right && a[left] <= a[keyi])
		{
			left++;
		}	

		Swap(&a[left], &a[right]);
	}

	Swap(&a[keyi], &a[left]);
	return left;
}
//快速排序
void QuickSort1(int* a, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}

	int keyi = PartSort1(a, begin, end);

	QuickSort1(a, begin, keyi - 1);
	QuickSort1(a, keyi+1, end);
}

 

3.2 挖坑版

 先设立基准值和一个临时变量,这个临时变量我们称为 坑位。接下来的操作跟hore版本有些类似,唯一不同的是我们需要把遍历出来的数据放入坑位,而因为数据被转移出去形成的空位就自然而然的变成新的坑位。最后,当left 和 right 相遇时,把基准值放入最后一个空出来的位置中。

 

//快排--单次排序(挖坑法)
int PartSort3(int* a, int left, int right)
{ 

	int key = a[left];
	// 保存key值以后,左边形成第一个坑
	int hole = left;

	while (left < right)
	{
		// 右边先走,找小,填到左边的坑,右边形成新的坑位
		while (left < right && a[right] >= key)
		{
			--right;
		}
		a[hole] = a[right];
		hole = right;

		// 左边再走,找大,填到右边的坑,左边形成新的坑位
		while (left < right && a[left] <= key)
		{
			++left;
		}
		a[hole] = a[left];
		hole = left;
	}

	a[hole] = key;
	return hole;
}
//快速排序
void QuickSort1(int* a, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}

	int keyi = PartSort3(a, begin, end);

	QuickSort1(a, begin, keyi - 1);
	QuickSort1(a, keyi+1, end);
}

 

 3.3 前后指针版

 

 

//快排--单次排序(前后指针)
int PartSort4(int* a, int left, int right)
{
	int keyi = left;
	int prev = keyi;
	int cur = prev + 1;

	while (cur <= right)
	{
		if (a[cur] < a[keyi] && ++prev != cur)
		{
			Swap(&a[prev], &a[cur]);
		}
		++cur;		
	}
	Swap(&a[prev], &a[keyi]);
	return prev;
}
//快速排序
void QuickSort1(int* a, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}

	int keyi = PartSort4(a, begin, end);

	QuickSort1(a, begin, keyi - 1);
	QuickSort1(a, keyi+1, end);
}

4、 快速排序的优化

4.1  三数取中来选取基准值key

从待排序数组中,选取开头、结尾和中间的数来进行比较。选择这三个数中不大不小的那一个并将其设为基准值key。

那么为什么要取中间呢?我们可以假设待排序的数列是一组高度有序的数列,显然首极大可能是最小值,尾极大可能是最大值,此时如果我们选取一个排在中间的值,哪怕是在最坏的情况下,begin和end只需要走到中间位置,那么这个中间值的位置也就确定下来,而不需要begin或end指针要把整个数列遍历一遍,从而大大提高快速排序的效率。

//三数取中 -- 取三个数中不大也不小的那个数
int GetMidi(int* a, int left, int right)
{
	int mid = (left + right) / 2;

	if (a[left] < a[mid])
	{
		if (a[mid] < a[right])
		{
			return mid;
		}
		else if (a[left] > a[right])  //a[mid]最大
		{
			return left;
		}
		else
		{
			return right;
		}
	}
	else
	{
		if (a[mid] > a[right])
		{
			return mid;
		}
		else if (a[left] > a[right])	//a[mid]最小
		{
			return right;
		}
		else
		{
			return left;
		}
	}
}

 

4.2 当待排序的数据量较小时,可以使用直接插入排序来代替快排

当快速排序递归到只剩较小的区间时,我们就可以使用直接插入排序。这样子,小区间就不用递归分割排序,降低递归次数。

void QuickSort2(int* a, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}

	// 小区间优化,小区间不再递归分割排序,降低递归次数
	if ((end - begin + 1) > 10)
	{
		int keyi = PartSort4(a, begin, end);

		// [begin, keyi-1] keyi [keyi+1, end]
		QuickSort2(a, begin, keyi - 1);
		QuickSort2(a, keyi + 1, end);
	}
	//当数组中数据量较小时,可直接用插入排序
	else
	{
		InsertSort(a + begin, end - begin + 1);
	}
}

 

 4.3 快速排序的非递归写法

 

非递归写法理解:

 

 


//快排非递归写法
void QuickSortNonR(int* a, int begin, int end)
{
	ST st;
	STInit(&st);
	//先放入数组中最后一个数的下标,再放入第一个数的下标(也就是右边界和左边界)
	STPush(&st, end);
	STPush(&st, begin);

	while (!STEmpty(&st))
	{
		int left = STTop(&st);
		STPop(&st);

		int right = STTop(&st);
		STPop(&st);

		int keyi = PartSort2(a, left, right);
		if (keyi + 1 < right)
		{
			STPush(&st, right);
			STPush(&st, keyi + 1);
		}

		if (left < keyi - 1)
		{
			STPush(&st, keyi - 1);
			STPush(&st, left);
		}
	}

	STDestroy(&st);
}

 

 

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

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

相关文章

Java Selenium入门程序

需求&#xff1a;使用chrome浏览器打开百度首页 1.配置浏览器驱动 &#xff08;1&#xff09;下载浏览器驱动&#xff0c;浏览器版本需与驱动版本一致&#xff1b; &#xff08;2&#xff09;编辑系统环境变量-->编辑Path-->填入浏览器驱动路径&#xff1a; 2.maven工…

【反悔贪心 反悔堆】1642. 可以到达的最远建筑

本文涉及知识点 反悔贪心 反悔堆 LeetCode1642. 可以到达的最远建筑 给你一个整数数组 heights &#xff0c;表示建筑物的高度。另有一些砖块 bricks 和梯子 ladders 。 你从建筑物 0 开始旅程&#xff0c;不断向后面的建筑物移动&#xff0c;期间可能会用到砖块或梯子。 当…

刷题之删除有序数组中的重复项(leetcode)

删除有序数组中的重复项 这题简单题&#xff0c;双指针&#xff0c;一个指针记录未重复的数的个数&#xff0c;另一个记录遍历的位置。 以下是简单模拟&#xff0c;可以优化&#xff1a; class Solution { public:int removeDuplicates(vector<int>& nums) {int l0…

STL--求交集,并集,差集(set_intersection,set_union,set_difference)

set_intersection(重要) 求两个有序的序列的交集. 函数声明如下: template<class InputIterator1, class InputIterator2, class OutputIterator>OutputIterator set_intersection(InputIterator1 _First1, //容器1开头InputIterator1 _Last1, //容器2结尾(不包含)Inp…

ChatGPT4深度解析:探索智能对话新境界

大模型chatgpt4分析功能初探 目录 1、探测目的 2、目标变量分析 3、特征缺失率处理 4、特征描述性分析 5、异常值分析 6、相关性分析 7、高阶特征挖掘 1、探测目的 1、分析chat4的数据分析能力&#xff0c;提高部门人效 2、给数据挖掘提供思路 3、原始数据&#xf…

Navicat终于免费了, 但是这个结果很奇葩

个人用下载地址: 点呀 好家伙, 每个机构最多5个用户, 对于正在审计的公司…

DAY1: 实习前期准备

文章目录 VS Code安装的插件C/CCMakeGitHub CopilotRemote-SSH收获 VS Code 下载链接&#xff1a;https://code.visualstudio.com 安装的插件 C/C 是什么&#xff1a;C/C IntelliSense, debugging, and code browsing. 为什么&#xff1a;初步了解如何在VS Code里使用C输出…

Vulnhub-Os-hackNos-1(包含靶机获取不了IP地址)

https://download.vulnhub.com/hacknos/Os-hackNos-1.ova #靶机下载地址 题目&#xff1a;要找到两个flag user.txt root.txt 文件打开 改为NAT vuln-hub-OS-HACKNOS-1靶机检测不到IP地址 重启靶机 按住shift 按下键盘字母"E"键 将图中ro修改成…

筛选Github上的一些优质项目

每个项目旁都有标签说明其特点&#xff0c;如今日热捧、多模态、收入生成、机器人、大型语言模型等。 项目涵盖了不同的编程语言和领域&#xff0c;包括人工智能、语言模型、网页数据采集、聊天机器人、语音合成、AI 代理工具集、语音转录、大型语言模型、DevOps、本地文件共享…

7-6 每日升学消息汇总

复旦附中清北比例大涨&#xff0c;从统计数据来看&#xff0c;今年复附的清北人数将创历史新高&#xff0c;达到前所未有年进43人。离上海7月9号中考出分&#xff0c;还有3天。小道消息说&#xff0c;画狮的数游天下又回来了&#xff0c;目前还未官方消息。2024第二届国际数学夏…

安卓虚拟位置修改1.25beta支持路线模拟、直接定位修改

导语:更新支持安卓14/15&#xff0c;支持路线模拟、直接定位修改&#xff0c;仅支持单一版本 无root需根据教程搭配下方链接所提供的虚拟机便可进行使用 有root且具备XP环境可直接真机运行 如你有特殊需求 重启问题设置打开XP兼容 针对具有虚拟机检测的软件 建议如下 度娘搜索…

多表查询sql

概述&#xff1a;项目开发中,在进行数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于业务之间相互关联,所以各个表结构之间也存在着各种联系&#xff0c;分为三种&#xff1a; 一对多多对多一对一 一、多表关系 一对多 案例&#xff1a;部门与…

在CMD中创建虚拟环境并在VSCode中使用和管理

1. 使用Conda创建虚拟环境 在CMD或Anaconda Prompt中执行以下代码以创建一个新的虚拟环境&#xff1a; conda create -n my_env python 3.8 这样会创建一个名为 my_env 的环境&#xff0c;并在Anaconda环境目录下生成一个相应的文件夹&#xff0c;包含该虚拟环境所需的所有…

STM32-ADC+DMA

本内容基于江协科技STM32视频学习之后整理而得。 文章目录 1. ADC模拟-数字转换器1.1 ADC模拟-数字转换器1.2 逐次逼近型ADC1.3 ADC框图1.4 ADC基本结构1.5 输入通道1.6 规则组的转换模式1.6.1 单次转换&#xff0c;非扫描模式1.6.2 连续转换&#xff0c;非扫描模式1.6.3 单次…

时间、查找、打包、行过滤与指令的运行——linux指令学习(二)

前言&#xff1a;本节内容标题虽然为指令&#xff0c;但是并不只是讲指令&#xff0c; 更多的是和指令相关的一些原理性的东西。 如果友友只想要查一查某个指令的用法&#xff0c; 很抱歉&#xff0c; 本节不是那种带有字典性质的文章。但是如果友友是想要来学习的&#xff0c;…

如何确保 PostgreSQL 在高并发写操作场景下的数据完整性?

文章目录 一、理解数据完整性二、高并发写操作带来的挑战三、解决方案&#xff08;一&#xff09;使用合适的事务隔离级别&#xff08;二&#xff09;使用合适的锁机制&#xff08;三&#xff09;处理死锁&#xff08;四&#xff09;使用索引和约束&#xff08;五&#xff09;批…

系统学习ElastricSearch(一)

不知道大家在项目中是否使用过ElastricSearch&#xff1f;大家对它的了解又有多少呢&#xff1f;官网的定义&#xff1a;Elasticsearch是一个分布式、可扩展、近实时的搜索与数据分析引擎。今天我们就来揭开一下它的神秘面纱&#xff08;以下简称ES&#xff09;。 ES 是使用 J…

uniapp零基础入门Vue3组合式API语法版本开发咸虾米壁纸项目实战

嗨&#xff0c;大家好&#xff0c;我是爱搞知识的咸虾米。 今天给大家带来的是零基础入门uniapp&#xff0c;课程采用的是最新的Vue3组合式API版本&#xff0c;22年发布的uniappVue2版本获得了官方推荐&#xff0c;有很多同学等着我这个vue3版本的那&#xff0c;如果没有学过vu…

CH12_函数和事件

第12章&#xff1a;Javascript的函数和事件 本章目标 函数的概念掌握常用的系统函数掌握类型转换掌握Javascript的常用事件 课程回顾 Javascript中的循环有那些&#xff1f;Javascript中的各个循环特点是什么&#xff1f;Javascript中的各个循环语法分别是什么&#xff1f;…

网页封装APP:让您的网站变身移动应用

网页封装APP&#xff1a;让您的网站变身移动应用 随着移动设备的普及&#xff0c;越来越多的人开始使用移动设备浏览网站。但是&#xff0c;传统的网站设计并不适合移动设备的屏幕尺寸和交互方式&#xff0c;这导致了用户体验不佳和流失。 有没有办法让您的网站变身移动应用&…