【数据结构】快排之三路划分

news2025/1/10 20:49:25

目录

一、前言

二、 快排性能的关键点分析

三、 三路划分基本思想

四、 思路分析

五、提醒

六、代码实现


一、前言

继续对快速排序的深入优化进行探讨

二、 快排性能的关键点分析

决定快排性能的关键点是每次单趟排序后,key对数组的分割。

如果每次选key都能做到基本二分居中,那么快排的递归树就是棵均匀的满二叉树,性能最佳。虽然实践中不能做到每次都二分居中,但是性能也还是可控的。

但如果每次选到最大值/最小值,划分0个和n-1的子问题时,时间复杂度就为O(N^2),当数组序列有序时就会出现这样的问题。前面已经用三数取中or随机选key解决了该问题。

但是,有些场景下hoae和lomuto(前后指针法)还是适应的不是很好,就是当数组中有大量重复数据时,该场景下性能是有些退化的。

针对数组中有大量重复数据的问题,我们采用三路划分的方式来解决。

三、 三路划分基本思想

那什么是三路划分呢?

在之前快排是排完序把key放在中间,左边比key值小,右边比key大,跟key相等的值在哪里并没有规定,跟key相等的值可以在左边,也可以在右边。

三路划分的基本思想是将数组分为三个部分:

当面对有大量跟key相同的值时,三路划分的核心思想类似hoare的左右指针和lomuto的前后指针的结合。核心思想是把数组中的数据分为三段:

小于基准元素key的放在左边

等于基准元素key的全部放在中间

大于基准元素key的放在右边

所以叫做三路划分算法。

通过三路划分的方式,可以避免在数组中有大量重复元素时出现的性能问题。

四、 思路分析

基本思路如下:

这里跟lomuto的前后指针法相结合(排升序)

  • key默认取left位置的值
  • left指向区间第一个元素位置,right指向区间最后一个元素位置,cur指向left+1的位置
  • 对cur进行判断
  1. 如果cur<key,cur指向的值与left位置的值进行交换,然后left++,cur++
  2. 如果cur>key,cur指向的值与right位置的值进行交换,然后right--
  3. 如果cur==key,cur++
  • 直到cur>right结束,排完单趟

结合图进行分析:

五、提醒

为什么cur==right要继续呢?

因为假如cur没有遇见比key大的值,right没有--,那么cur与right在相同位置时,并不能确定right所指向的值是否小于key。

例如下图的情况:

六、代码实现

//交换算法
void swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

//三数取中
int GetMidi(int* a, int left, int right)
{
	int midi = (left + right) / 2;

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

//三路划分算法
void QuickSort_Three_Way_Partition(int* a, int left, int right) //参数为数组下标
{
	if (left >= right)
	{
		return;
	}

	int midi = GetMidi(a, left, right);
	swap(&a[left], &a[midi]);

		int begin = left;
		int end = right;
		int key = a[left];
		int cur = left + 1;

		while (cur <= end)
		{
			if (a[cur] < key)
			{
				swap(&a[cur], &a[begin]);
				begin++;
				cur++;
			}
			else if (a[cur] > key)
			{
				swap(&a[cur], &a[end]);
				end--;
			}
			else if (a[cur] == key)
			{
				cur++;
			}
		}		

		//递归左右区间
		QuickSort_Three_Way_Partition(a, left,begin-1);
		QuickSort_Three_Way_Partition(a, end+1, right);
}

int main()
{
	int arr[] = {7,13,6,2,7,7,23,7,7,98,11,6,9,1,66,21,5};
    int sz = sizeof(arr) / sizeof(arr[0]);

    QuickSort_Three_Way_Partition(arr,0,sz-1);

	return 0;
}

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

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

相关文章

Web安全之SQL注入---基础

文章目录 SQL注入简介SQL注入基础SQL注入分类SQL注入流程 SQL注入简介 什么是SQL注入&#xff1f; SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严&#xff0c;攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句&#xff0c;在管理…

iOS 18.1,未公开的新功能

童锦程祖师爷曾说过&#xff1a;“发誓可以&#xff0c;发朋友圈不行。”表面上看是渣男语录&#xff0c;实际上也说明了人们对隐私的看重。 在当今生活中&#xff0c;智能手机可能是最私密的电子产品&#xff0c;没有之一。不管是照片、联系人、短信、APP数据&#xff0c;甚至…

网页版五子棋——对战模块(服务器端开发②)

前一篇文章&#xff1a;网页版五子棋——对战模块&#xff08;服务器端开发①&#xff09;-CSDN博客 项目源代码&#xff1a;Java: 利用Java解题与实现部分功能及小项目的代码集合 - Gitee.com 目录 前言 一、创建并注册 GameAPI 类 1.创建 GameAPI 类 2.注册 GameAPI 类 …

★ C++进阶篇 ★ 异常

Ciallo&#xff5e;(∠・ω< )⌒☆ ~ 今天&#xff0c;我将和大家一起学习C中的异常 ~ ​❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️ 澄岚主页&#xff1a;椎名澄嵐-CSDN博客 C基础篇专栏&#xff1a;★ C基础篇 ★_椎名澄嵐的博客-CSDN博客 C进阶篇专栏&am…

MFC图形函数学习08——绘图函数的重载介绍

在《MFC图形函数学习06——画椭圆弧线函数》中介绍了CPoint类、POINT结构体&#xff1b;在《MFC图形函数学习07——画扇形函数》中介绍了CRect类、RECT结构体。在介绍完后&#xff0c;没有介绍它们怎样使用。实际上&#xff0c;这些类和结构体对象或指针也是我们学习过的绘图函…

尽量通俗易懂地概述.Net U nity跨语言/跨平台相关知识

本文参考来自唐老狮,Unity3D高级编程:主程手记,ai等途径 仅作学习笔记交流分享 目录 1. .Net是什么? 2. .Net框架的核心要点? 跨语言和跨平台 .Net x Unity跨平台发展史 Net Framework 2002 Unity跨平台之 Mono 2004 Unity跨平台之 IL2CPP 2015 二者区别 .NET Core …

Flink执行sql时报错

[ERROR] Could not execute SQL statement. Reason: java.lang.ClassNotFoundException: org.apache.flink.table.planner.delegation.ParserFactory flink-1.15.4的lib里面存在flink-sql-connector-hive-3.1.2_2.12-1.15.4.jar时&#xff0c;似乎会跟hdfs产生冲突&#xff0c…

实现API接口的自动化

API接口自动化测试的最佳实践有哪些&#xff1f; API接口自动化测试的最佳实践包括以下几个方面&#xff1a; 确定测试范围和目标&#xff1a;明确需要测试的API接口和功能点&#xff0c;确定测试的目标和预期结果 编写测试用例&#xff1a;根据API文档和需求&#xff0c;编…

uni-app中使用 unicloud 云开发平台③

文章目录 六、hbuilderX 中使用 unicloud 云开发平台文档传统业务开发流程什么是 unicloudunicloud 优点开发流程uncloud 构成云数据库云存储及 CDN创建云函数工程七、unicloud api 操作云函数调用云函数实现云数据库基本增删改查1. 获取数据库引用云存储操作六、hbuilderX 中使…

【缓存策略】你知道 Refresh-ahead(预刷新)这个缓存策略吗?

👉博主介绍: 博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家,WEB架构师,阿里云专家博主,华为云云享专家,51CTO 专家博主 ⛪️ 个人社区:个人社区 💞 个人主页:个人主页 🙉 专栏地址: ✅ Java 中级 🙉八股文专题:剑指大厂,手撕 J…

零基础Java第十六期:抽象类接口(二)

目录 一、接口&#xff08;补&#xff09; 1.1. 数组对象排序 1.2. 克隆接口 1.3. 浅拷贝和深拷贝 1.4. 抽象类和接口的区别 一、接口&#xff08;补&#xff09; 1.1. 数组对象排序 我们在讲一维数组的时候&#xff0c;使用到冒泡排序来对数组里的元素进行从小到大或从大…

django入门【05】模型介绍(二)——字段选项

文章目录 1、null 和 blank示例说明⭐ null 和 blank 结合使用的几种情况总结&#xff1a; 2、choices**choices 在 Django 中有以下几种形式&#xff1a;**&#xff08;1&#xff09; **简单的列表或元组形式**&#xff08;2&#xff09; **字典映射形式**&#xff08;3&#…

数据量大Excel卡顿严重?选对报表工具提高10倍效率

当几万行的数据把软件频频跑崩&#xff0c;当珍贵的数据资源无法便捷复用&#xff0c;当数据填报的本地文档在各个电脑中传来传去……在各大岗位要求中频频出现的Excel&#xff0c;作为个人办公软件绝无仅有&#xff0c;但作为企业场景下的报表工具&#xff0c;效率显然不足。 …

如何用WordPress和Shopify提升SEO表现?

选择合适的建站程序对于SEO优化非常重要。目前&#xff0c;WordPress和Shopify是两种备受推崇的建站平台&#xff0c;各有优势。 WordPress最大的优点是灵活性。它支持大量SEO插件&#xff0c;帮助你调整元标签、生成站点地图、优化内容结构等。这些功能让你能够轻松地提升网站…

vue 计算属性get set

<template><div id"app"><h1>用户信息</h1><p>全名&#xff1a;{{ fullName }}</p><input v-model"fullName" placeholder"请输入全名" /><p>姓&#xff1a;{{ firstName }}</p><p>…

PHP搭建开发环境(Windows系统)

要搭建一个完整的PHP动态网站&#xff0c;离不开操作系统、Web服务器、数据库、和PHP软件。 虽然有不错方便的方式&#xff0c;比如使用phpstudio等等等等许多面板都是非常快速不错的方式&#xff0c;但是这里是教会大家如何配置而不只是依赖别人整合好的面板软件&#xff0c;…

7.2 图像复原之空间滤波

图像复原&#xff08;只存在噪声的复原&#xff09;之空间滤波 文章目录 图像复原&#xff08;只存在噪声的复原&#xff09;之空间滤波前言1. 均值滤波器1.1 算术平均滤波器1.2 几何均值滤波器1.3 谐波平均滤波器1.4 反谐波平均滤波器 总结 前言 当一幅图像仅被加性噪声退化时…

化工防爆巡检机器人:在挑战中成长,为化工安全保驾护航

随着全球能源需求的不断攀升&#xff0c;化工行业的安全性与高效性愈发受到关注。化工设施规模巨大&#xff0c;而且其中多数存在高风险因素&#xff0c;像是易燃易爆化学物质、高温环境、有毒有害物质以及高压设备等。仅2023年&#xff0c;国内危化品事故就多达652起&#xff…

【数字图像处理+MATLAB】对图片进行伽马校正(Gamma Correction):使用幂律变换公式进行伽马变换

引言 伽马校正&#xff08;Gamma Correction&#xff09;是一种用于图像处理的技术&#xff0c;主要用于调整图像的亮度或对比度。其基本原理是对图像的每一个像素应用一个非线性变换&#xff0c;以更好地适应人眼的视觉感知。在数字图像处理中&#xff0c;伽马校正通常用于调…

scala 迭代更新

在Scala中&#xff0c;迭代器&#xff08;Iterator&#xff09;是一种用于遍历集合&#xff08;如数组、列表、集合等&#xff09;的元素而不暴露其底层表示的对象。迭代器提供了一种统一的方法来访问集合中的元素&#xff0c;而无需关心集合的具体实现。 在Scala中&#xff0c…