【数据结构】排序--快速排序

news2025/7/13 18:55:42

目录

一 概念

二 快速排序的实现

1. hoare版本

(1)代码实现

(2)单趟排序图解

(3) 递归实现图解

(4)细节控制

(5)时间复杂度

(6)三数取中优化

 2 挖坑法

(1)代码实现

(2)单趟图解 

3 前后指针法 

(1) 代码实现 

(2) 单趟图解

​编辑4 优化子区间 

5 非递归快速排序

​ 三 快速排序的特性总结


一 概念

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

二 快速排序的实现

上述为快速排序递归实现的主框架,发现与二叉树前序遍历规则非常像

1. hoare版本

(1)代码实现

#include<stdio.h>
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

int PartSort1(int* a, int left, int right)
{
	int keyi = left;
	while (left < right)
	{
		//找小
		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 QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	int key = PartSort1(a, begin, end);
	QuickSort(a, begin, key - 1);
	QuickSort(a, key + 1, end);
}
int main()
{
	int arr[] = {6,1,2,7,9,3,4,5,10,8};
	QuickSort(arr, 0, (sizeof(arr) / sizeof(int)) - 1);
	for (int i = 0; i < sizeof(arr) / sizeof(int); i++)
	{
		printf("%d ", arr[i]);
	}
}

(2)单趟排序图解

我们看看单趟排序怎么排的

 

(3) 递归实现图解

再来看看递归怎么实现的

 

(4)细节控制

对细节控制上 我要做一下解释

 那这里相遇位置一定比a[keyi]小呢?  右边先走导致的

(5)时间复杂度

我们来算一下快速排序的时间复杂度(需要对二叉树的基本性质熟悉)

 

(6)三数取中优化

那针对有序 的情况 我们可以采取三数取中的方式解决

#include<stdio.h>
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

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])
		{
			return left;
		}
		else
		{
			return right;
		}
	}

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

int PartSort1(int* a, int left, int right)
{
	int midi = GetMidi(a, left, right);
	Swap(&a[midi], &a[left]);
	int keyi = left;
	while (left < right)
	{
		//找小
		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 QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	int key = PartSort1(a, begin, end);
	QuickSort(a, begin, key - 1);
	QuickSort(a, key + 1, end);
}
int main()
{
	int arr[] = {6,1,2,7,9,3,4,5,10,8};
	QuickSort(arr, 0, (sizeof(arr) / sizeof(int)) - 1);
	for (int i = 0; i < sizeof(arr) / sizeof(int); i++)
	{
		printf("%d ", arr[i]);
	}
}

 2 挖坑法

  (1)代码实现

#include<stdio.h>
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

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])
		{
			return left;
		}
		else
		{
			return right;
		}
	}

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


int PartSort2(int* a, int left, int right)
{
	int midi = GetMidi(a, left, right);
	Swap(&a[left], &a[midi]);

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

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

		a[hole] = a[right];
		hole = right;

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

void QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	int key = PartSort2(a, begin, end);
	QuickSort(a, begin, key - 1);
	QuickSort(a, key + 1, end);
}
int main()
{
	int arr[] = {6,1,2,7,9,3,4,5,10,8};
	QuickSort(arr, 0, (sizeof(arr) / sizeof(int)) - 1);
	for (int i = 0; i < sizeof(arr) / sizeof(int); i++)
	{
		printf("%d ", arr[i]);
	}
}

(2)单趟图解 

3 前后指针法 

(1) 代码实现 

int PartSort3(int* a, int left, int right)
{
	int keyi = left;
	int prev = left;
	int cur = prev + 1;
	while (cur <= right)
	{
		if (a[cur] < a[keyi] && ++prev != cur)
		{
			Swap(&a[cur], &a[prev]);
		}
		cur++;
	}
	Swap(&a[keyi], &a[prev]);
	return prev;
}
void QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}
	int key = PartSort3(a, begin, end);
	QuickSort(a, begin, key - 1);
	QuickSort(a, key + 1, end);
}
int main()
{
	int arr[] = {6,1,2,7,9,3,4,5,10,8};
	QuickSort(arr, 0, (sizeof(arr) / sizeof(int)) - 1);
	for (int i = 0; i < sizeof(arr) / sizeof(int); i++)
	{
		printf("%d ", arr[i]);
	}
}

(2) 单趟图解

4 优化子区间 

递归到小的子区间时, 不在递归分割排序,可以考虑使用插入排序

因为区间比较小的时候节点数开的很多  特别是最后一层 节点数占了整个数大致百分之五十

 

int PartSort(int* a, int left, int right)
{
	int midi = GetMidi(a, left, right);
	Swap(&a[left], &a[midi]);


	int keyi = left;
	int prev = left;
	int cur = prev + 1;
	while (cur <= right)
	{
		if (a[cur] < a[keyi] && ++prev != cur)
		{
			Swap(&a[cur], &a[prev]);
		}
		cur++;
	}
	Swap(&a[prev], &a[keyi]);
	return prev;
}



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

	if ((end - begin + 1) > 10)
	{
		int keyi = PartSort(a, begin, end);
		QuickSort(a, begin, keyi - 1);
		QuickSort(a, keyi + 1, end);
	}
	else
	{
		//插入排序
		InsertSort(a + begin, end - begin + 1);
	}
}

5 非递归快速排序

需要有对栈的基础  不会的可以看前面的博客

#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<assert.h>
typedef struct STList
{
	int* a;
	int size;
	int capacity;
}ST;

void STInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->size = ps->capacity = 0;
}

void STDestroy(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->size = ps->capacity = 0;
}
void STPush(ST* ps, int x)
{
	assert(ps);
	if (ps->size == ps->capacity)
	{
		int newcapacity = (ps->capacity == 0 ? 4 : ps->capacity * 2);
		int* tmp = (int*)realloc(ps->a, sizeof(int) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}
	ps->a[ps->size] = x;
	ps->size++;
}

void STPop(ST* ps)
{
	assert(ps);
	assert(ps->size > 0);
	ps->size--;
}

bool STEmpty(ST* ps)
{
	assert(ps);
	return ps->size == 0;
}

int STTop(ST* ps)
{
	assert(ps);
	assert(ps->size > 0);
	return ps->a[ps->size - 1];
}
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

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])
		{
			return left;
		}
		else
		{
			return right;
		}
	}

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

int PartSort(int* a, int left, int right)
{
	int midi = GetMidi(a, left, right);
	Swap(&a[left], &a[midi]);


	int keyi = left;
	int prev = left;
	int cur = prev + 1;
	while (cur <= right)
	{
		if (a[cur] < a[keyi] && ++prev != cur)
		{
			Swap(&a[cur], &a[prev]);
		}
		cur++;
	}
	Swap(&a[prev], &a[keyi]);
	return prev;
}



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 = PartSort(a, left, right);
		// [lefy,keyi-1] keyi [keyi+1, 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);
}

int main()
{
	int arr[] = {6,1,2,7,9,3,4,5,10,8};
	QuickSortNonR(arr, 0, (sizeof(arr) / sizeof(int)) - 1);
	for (int i = 0; i < sizeof(arr) / sizeof(int); i++)
	{
		printf("%d ", arr[i]);
	}
}

 三 快速排序的特性总结

1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序

2. 时间复杂度:O(N*logN)

3. 空间复杂度:O(logN)

4. 稳定性:不稳定

本节难度还是不低, 但是我觉得大家根据图解和代码慢慢吃透还是不难的,这节我画的图解很多, 对重点和难点进行了很细致的划分和讲解, 希望大家可以窥探到快速排序的妙处

继续加油!

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

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

相关文章

零基础Linux_18(进程间通信)共享内存+消息队列+信号量

目录 1. 共享内存 1.1 共享内存概念 1.2 系统函数shmget 1.2.1 key值和ftok 1.2.2 sizeshmflg返回值 1.3 系统调用shmctl 1.4 系统调用shmat和shmdt 1.5 共享内存进程间通信前期代码 1.6 共享内存进程间通信 2. 消息队列(了解) 3. 信号量(了解) 4. 笔试选择题 答案…

git的介绍和安装、常用命令、忽略文件、分支

git介绍和安装 首页功能写完了 ⇢ \dashrightarrow ⇢ 正常应该提交到版本仓库 ⇢ \dashrightarrow ⇢ 大家都能看到这个 ⇢ \dashrightarrow ⇢ 运维应该把现在这个项目部署到测试环境中 ⇢ \dashrightarrow ⇢ 测试开始测试 ⇢ \dashrightarrow ⇢ 客户可以看到目前做的…

137. 只出现一次的数字 II (中等。位运算)

不会做&#xff0c;思路来自官解 对于每一位来说&#xff0c;每个数字只能是 0 或 1&#xff0c;如果所有数字的第 i 位和能被3整除&#xff0c;那么表示只出现一次的这个元素在这一位上为0&#xff0c;反之就是1 class Solution:def singleNumber(self, nums: List[int]) -&g…

java.math.BigDecimal cannot be cast to java.lang.String

1.数据库&#xff1a; oracle 数据类型&#xff1a; NUMBER 2.java代码示例 List<Map<String, String>> list new ArrayList<>(); 错误&#xff1a; String nchangestdrate list.get(i).get(“rate”); 或者 BigDecimal nchangestdrate (BigDecimal)li…

【扩散模型从原理到实战】Chapter2 Hugging Face简介

文章目录 Hugging Face的核心功能介绍Hugging Face开源库Hugging Face开源库Gradio工具介绍参考资料 Hugging Face是机器学习从业者协作和交流的平台&#xff0c;成立于2016年&#xff0c;在纽约和巴黎设有办事处&#xff0c;团队成员来自世界各地&#xff0c;远程办公。 致力于…

程序员凭本事赚钱被没收所得,是否体现了“重刑主义”?

近日&#xff0c;承德程序员翻墙“打工”被罚款一事冲上热搜&#xff0c;热度不减。 1.人们同情该程序员的不幸遭遇&#xff0c;为他鸣不平&#xff1b; 2.包括程序员群体在内的大众关心此事背后的谋生问题&#xff1b; 3.引发了大众对承德执法的反思与质疑&#xff1b; 4.甚至…

【QT开发(8)】QT 中使用tensorrt

在之前的文章《【TensorRT&#xff08;2&#xff09;】研究美团tech的yolov6的TensorRT部署》说明了tensorRT 的使用流程。今天尝试将其并入QT 项目中。 文章目录 项目地址参考资料&#xff1a;该分支主要做的工作Task 1:读取视频文件&#xff0c;然后通过 dds 发送的事情Task…

2008-2017年上市公司海外收入数据

2008-2017年上市公司海外收入数据 1、时间&#xff1a;2008-2017年 2、指标&#xff1a;上市公司海外收入 3、范围&#xff1a;A股 4、来源&#xff1a;WIND 5、指标解释&#xff1a; 上市公司&#xff08;The listed company&#xff09;&#xff0c;根据《公司法》第四…

交通目标检测-行人车辆检测流量计数 - 计算机竞赛

文章目录 0 前言1\. 目标检测概况1.1 什么是目标检测&#xff1f;1.2 发展阶段 2\. 行人检测2.1 行人检测简介2.2 行人检测技术难点2.3 行人检测实现效果2.4 关键代码-训练过程 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 毕业设计…

MySQL——七、MySQL备份恢复

MySQL 一、MySQL日志管理1、MySQL日志类型2、错误日志3、通用查询日志4、慢查询日志5、二进制日志5.1 开启日志5.2 二进制日志的管理5.3 日志查看5.4 二进制日志还原数据 二、MySQL备份1、备份类型逻辑备份优缺点 2、备份内容3、备份工具3.1 MySQL自带的备份工具3.2 文件系统备…

做接口测试的流程一般是怎么样的?UI功能6大流程、接口测试8大流程这些你真的全会了吗?

在讲接口流程测试之前&#xff0c;首先需要给大家申明下&#xff1a;接口测试对于测试人员而言&#xff0c;非常非常重要&#xff0c;懂功能测试接口测试&#xff0c;就能在企业中拿到一份非常不错的薪资。 这么重要的接口测试&#xff0c;一般也是面试笔试必问。为方便大家更…

k8s-20 hpa控制器

hpa可通过metrics-server所提供pod的cpu 或者内存的负载情况&#xff0c;从而动态拉伸控制器的副本数&#xff0c;从而达到后端的自动弹缩 官网&#xff1a;https://kubernetes.io/zh-cn/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/ 上传镜像 压测 po…

模型量化笔记--KL散度量化

KL散度量化 前面介绍的非对称量化中&#xff0c;是将数据中的min值和max值直接映射到[-128, 127]。 同样的&#xff0c;前面介绍的对称量化是将数据的最大绝对值 ∣ m a x ∣ |max| ∣max∣直接映射到127。 上面两种直接映射的方法比较粗暴&#xff0c;而TensorRT中的int8量化…

有没有好用的扫描爆破工具?来看这里

工具介绍 goon集合了fscan和kscan等优秀工具功能的扫描爆破工具。功能包含&#xff1a;ip探活、port扫描、web指纹扫描、title扫描、压缩文件扫描、fofa获取、ms17010、mssql、mysql、postgres、redis、ssh、smb、rdp、telnet、tomcat等爆破以及如netbios探测等功能。 参数说…

Linux高性能服务器编程 学习笔记 第十六章 服务器调制、调试和测试

Linux平台的一个优秀特性是内核微调&#xff0c;即我们可以通过修改文件的方式来调整内核参数。 服务器开发过程中&#xff0c;可能会碰到意想不到的错误&#xff0c;一种调试方法是用tcpdump抓包&#xff0c;但这种方法主要用于分析程序的输入和输出&#xff0c;对于服务器的…

Atlassian Confluence OGNL表达式注入RCE CVE-2021-26084

影响版本 All 4.x.x versions All 5.x.x versions All 6.0.x versions All 6.1.x versions All 6.2.x versions All 6.3.x versions All 6.4.x versions All 6.5.x versions All 6.6.x versions All 6.7.x versions All 6.8.x versions All 6.9.x versions All 6.1…

uniapp使用uQRCode绘制二维码,下载到本地,调起微信扫一扫二维码核销

1.效果 2.在utils文件夹下创建uqrcode.js // uqrcode.js //--------------------------------------------------------------------- // github https://github.com/Sansnn/uQRCode //---------------------------------------------------------------------let uQRCode {…

小学数学题AI自动出题系统源码,支持在线打印及导出PDF!

今天给大家开发了个好东西&#xff0c;小学数学作业练习册AI自动出题网站源码&#xff0c;全面支持打印机打印机转成PDF文件&#xff0c;快给你家娃娃整一套吧&#xff0c;AI自动出题&#xff0c;让娃练习算数&#xff0c;解放双手&#xff0c;让您的孩子成绩蒸蒸日上&#xff…

【微服务 SpringCloudAlibaba】实用篇 · Nacos注册中心

微服务&#xff08;5&#xff09; 文章目录 微服务&#xff08;5&#xff09;1. 认识和安装Nacos2. 服务注册到nacos和拉取服务1&#xff09;引入依赖2&#xff09;配置nacos地址3&#xff09;重启 3. 服务分级存储模型3.1 给user-service配置集群3.2 同集群优先的负载均衡 4. …

高程DEM-等高线生成-AutoCAD等高线

高程DEM-等高线生成-AutoCAD等高线 发布时间&#xff1a;2018-01-17 版权&#xff1a; 同步视频教程&#xff1a;卫星地图_高清卫星地图_卫星地图视频_下载高程等高线使用视频教程 专题地图制作视频教程&#xff1a;卫星地图_高清卫星地图_卫星地图视频_地图数据应用&#xf…