【排序算法】快速排序升级版--三路快排详解 + 实现(c语言)

🌟🌟作者主页:ephemerals__

🌟🌟所属专栏:算法

目录​​​​​​​

前言

一、三路快排的整体思路

二、三路快排的具体实现

1.测试数据、交换函数和三数取中法

2.三路快排函数

三、程序全部代码

总结


前言

        之前我们学习了快速排序算法及其实现:

【排序算法】八大排序(下)(c语言实现)(附源码)-CSDN博客

不过它的缺陷也很明显:当数组中存在大量相同元素时,那些与基准值相同的元素的划分方法是未定义的,这将导致运行效率的下降。基于此问题,今天给大家介绍快速排序的升级版--三路快排,它能够很大程度地解决大量数据相同的情况。

一、三路快排的整体思路

        所谓三路快排,就是从快速排序的划分上,由原来的两部分变为三部分:左边是比基准值小的数据;中间是与基准值相同的数据;右边是比基准值大的数据这样划分出来,之后递归细分时,每一次生成的中间部分就不需要再进行划分了,提高了整体的运行效率

       之前我们的快速排序当中,都是默认将数组首元素作为基准值如果该值是数组的最大值或者最小值,那么划分操作相当于只是将该值进行了排序,时间复杂度就会退化为O(N^2)。所以接下来我们在选取基准值时,将会使用三数取中法将首元素、末元素与中间元素进行比较,选取一个中间值作为基准值

        划分的具体步骤如下:

1. 创建两“指针” left 和 right ,分别指向待排区间的两端;找到基准值之后与left位置交换,让其位于首元素位置

2. 创建“指针” cur,指向left的后一个位置

3. 当cur遇到比基准值的元素时,其与left位置交换,然后cur和left各向后走一步

    当cur遇到比基准值的元素时,其与right位置交换,然后right向前走一步

    当cur遇到与基准值相同元素时,cur向后走一步,访问后面的元素

4. 当cur超过right位置时,划分结束,退出循环

我们画图模拟一下它的划分过程:

注意划分完成后left和right所处的位置,便于确定下次递归的区间。

二、三路快排的具体实现

        接下来,我们开始实现三路快排。首先写好测试数据、交换两元素的函数与三数取中法:

1.测试数据、交换函数和三数取中法

#include <stdio.h>int main()
{int arr[] = { 9,4,1,5,5,6,2,2,2,8,4,4,0,3,3,8,7 };//测试数据int sz = sizeof(arr) / sizeof(arr[0]);//计算出数组大小//这里排序数据for (int i = 0; i < sz; i++)//打印数组{printf("%d ", arr[i]);}return 0;
}
//交换两元素
void Swap(int* x, int* y)
{int tmp = *x;*x = *y;*y = tmp;
}
//三数取中法,返回中间值的下标
int MidOfThree(int* arr, int a, int b, int c)
{if (arr[a] > arr[b]){if (arr[b] > arr[c]){return b;}else if (arr[a] > arr[c]){return c;}else{return a;}}else{if (arr[a] > arr[c]){return a;}else if (arr[b] > arr[c]){return c;}else{return b;}}
}

2.三路快排函数

接下来,我们尝试实现三路快排的划分以及递归:

//三路快排
void QuickSort(int* arr, int left, int right)
{if (left >= right)//划分的区间达到最小,停止递归{return;}//记录左右边界与中间元素的下标int begin = left;int end = right;int mid = (begin + end) / 2;//确定基准值,并将其与首元素交换Swap(&arr[MidOfThree(arr, begin, mid, end)], &arr[left]);int key = arr[left];//记录基准值int cur = left + 1;//遍历数组,开始划分while (cur <= right){if (arr[cur] < key)//比基准值小的情况{Swap(&arr[cur++], &arr[left++]);}else if (arr[cur] > key)//比基准值大的情况{Swap(&arr[cur], &arr[right--]);}else//与基准值相等的情况{cur++;}}//划分完成后,递归遍历左区间和右区间,中间部分不需要再参与排序//注意此时left和right的位置QuickSort(arr, begin, left - 1);QuickSort(arr, right + 1, end);
}

测试结果:

可以看到,数组排序成功了。

三、程序全部代码

三路快排的相关程序全部代码如下:

#include <stdio.h>//交换两元素
void Swap(int* x, int* y)
{int tmp = *x;*x = *y;*y = tmp;
}//三数取中法,返回中间值的下标
int MidOfThree(int* arr, int a, int b, int c)
{if (arr[a] > arr[b]){if (arr[b] > arr[c]){return b;}else if (arr[a] > arr[c]){return c;}else{return a;}}else{if (arr[a] > arr[c]){return a;}else if (arr[b] > arr[c]){return c;}else{return b;}}
}//三路快排
void QuickSort(int* arr, int left, int right)
{if (left >= right)//划分的区间达到最小,停止递归{return;}//记录左右边界与中间元素的下标int begin = left;int end = right;int mid = (begin + end) / 2;//确定基准值,并将其与首元素交换Swap(&arr[MidOfThree(arr, begin, mid, end)], &arr[left]);int key = arr[left];//记录基准值int cur = left + 1;//遍历数组,开始划分while (cur <= right){if (arr[cur] < key)//比基准值小的情况{Swap(&arr[cur++], &arr[left++]);}else if (arr[cur] > key)//比基准值大的情况{Swap(&arr[cur], &arr[right--]);}else//与基准值相等的情况{cur++;}}//划分完成后,递归遍历左区间和右区间,中间部分不需要再参与排序//注意此时left和right的位置QuickSort(arr, begin, left - 1);QuickSort(arr, right + 1, end);
}int main()
{int arr[] = { 9,4,1,5,5,6,2,2,2,8,4,4,0,3,3,8,7 };//测试数据int sz = sizeof(arr) / sizeof(arr[0]);//计算出数组大小//这里排序数据QuickSort(arr, 0, sz - 1);for (int i = 0; i < sz; i++)//打印数组{printf("%d ", arr[i]);}return 0;
}

总结

        快速排序是一种高效且常用的排序算法,但是传统的快排并没有对与基准值相同的数据进行明确划分,造成运行效率的降低。因此出现了三路快排,它按照基准值将数组分成了三份:左边是比基准值小的数据;中间是与基准值相同的数据;右边是比基准值大的数据。这样,与基准值相同的数据就不需要再次划分,提高了整体的运行效率。如果你觉得博主讲的还不错,就请留下一个小小的赞在走哦,感谢大家的支持❤❤❤

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

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

相关文章

无线麦克风推荐哪些品牌,无线麦克风哪个品牌好,好的麦克风推荐

在声音创作与直播的领域里&#xff0c;无线领夹麦克风作为捕捉清晰声音的第一道防线&#xff0c;其重要性不言而喻。传统的有线麦克风及部分无线产品&#xff0c;难以在移动场景下提供稳定、清晰的录音效果&#xff1b;劣质无线领夹麦克风往往音质不稳定&#xff0c;甚至可能在…

数据库太慢跑崩的一大罪魁

就是非常不起眼的帐号去重计数&#xff0c;用 SQL 写就是 COUNT(DISTINCT …)。 帐号去重计数在商业分析中很常见也有重要的业务意义。这里的帐号可能是用户 ID、银行帐户、手机号、车牌号、…。计算逻辑基本一样&#xff0c;就是从某个时段的历史数据中统计出有多少个帐号满足…

缓存解决方案。Redis 和 Amazon ElastiCache 比较

欢迎来到雲闪世界。Redis 和 Amazon ElastiCache 等缓存解决方案是通过将频繁访问的数据存储在内存中来提高应用程序性能的热门选择。让我们从实施简单性、性能、成本和维护方面对它们进行比较。 实施简单 设置 Redis 需要在基础设施或云实例上安装和配置 Redis 服务器。它可…

解决 Android 上的 .NET MAUI/Xamarin.AndroidX 应用调用 ASP.NET Core API 端点时 SSL 连接被拒绝的问题

从虚拟机调用本地API报各种 SSL 连接不上的错误&#xff0c;这给本地调试造成了极大的不便&#xff0c;在被这个问题困扰了多日以后&#xff0c;终于在GitHub上找到答案 基于这个 帖子 &#xff0c;有一个回复 他写了一个帮助类&#xff0c;专门用来调试本地的API&#xff0c;…

常见的图纸加密软件方式:推荐10个最好用的图纸加密软件

在当今竞争激烈的商业环境中&#xff0c;保护设计图纸等敏感信息已成为企业不可忽视的任务。图纸加密软件作为一项重要的信息安全措施&#xff0c;不仅能够防止未经授权的访问&#xff0c;还能确保设计工作的机密性和完整性。面对市场上琳琅满目的加密软件&#xff0c;选择一款…

变压器结构

变压器结构提供磁路&#xff0c;通常称为“变压器铁芯”&#xff0c;旨在为磁场提供流动路径。该磁路对于两个输入和输出绕组之间感应电压必不可少。 然而&#xff0c;这种变压器结构&#xff08;两个绕组缠绕在不同的支路上&#xff09;效率不高&#xff0c;因为初级绕组和次…

Secret

Secret 在 Kubernetes 中&#xff0c;Secret 是一种用于存储敏感信息的资源&#xff0c;比如密码、OAuth 令牌、SSH 密钥等。Secret 允许你以安全的方式将这些信息传递给 Pod&#xff0c;而不是硬编码在镜像或配置文件中。 配置管理中心&#xff1a;configMap、Secret Secre…

数据库和MySQL

ER图 实体&#xff08;矩形&#xff09;&#xff1a;通常是现实世界的业务对象&#xff0c;当然使用一些逻辑对象也可以。 属性&#xff08;椭圆&#xff09;&#xff1a;实体拥有的属性。 联系&#xff08;菱形&#xff09;&#xff1a;实体与实体之间的关系。 函数依赖 函数依…

使用python+opencv解析图像和文本数据

1. 创建虚拟环境 新建文件夹, 并在文件夹中创建虚拟环境,可以使用Vscode打开文件夹, 然后在终端中输入以下命令: python -m venv venv2. 激活虚拟环境 在终端中输入以下命令: venv\Scripts\activate3. 安装依赖 在终端中输入以下命令: pip install opencv-pythonpip inst…

深度学习示例2-多输入多输出的神经网络模型

一、代码示例 from tensorflow import keras from tensorflow.keras import layers import numpy as np# 定义 多输入 多输出的模型 vocabulary_size = 1000 num_tags = 100 num_departments = 4title = keras.Input(shape=(vocabulary_size,), name = "title") tex…

kali——msfconsole的使用

目录 前言 msfconsole的使用基础 启动mfsconsole 各种辅助模块的使用 端口扫描模块&#xff08;portscan&#xff09; 查看端口扫描的模块 使用模块 查看所需设置 手动设置 执行 退出 各种漏洞模块的使用 nmap扫描主机漏洞 查看漏洞模块 使用漏洞模块 查看所需设…

Prometheus通过node_exporter监控Node节点,Node节点的详细指标解读

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

吴恩达深度学习笔记:卷积神经网络(Foundations of Convolutional Neural Networks)1.9-1.10

目录 第四门课 卷积神经网络&#xff08;Convolutional Neural Networks&#xff09;第一周 卷积神经网络&#xff08;Foundations of Convolutional Neural Networks&#xff09;1.9 池化层&#xff08;Pooling layers&#xff09;1.10 卷 积 神 经 网 络 示 例 &#xff08; …

Linux_kernel汇编驱动06

一、ARM汇编语言&#xff08;GUN-gcc编译器下&#xff09; 1、语句格式 {symbol} {instruction|directive|pseudo-instruction} { comment} symbol&#xff1a;为符号。 在ARM汇编语言中&#xff0c;符号必须从一行的行头开始&#xff0c;并且符号中不能包含空格。 在指令和伪指…

基于C++实现(MFC界面)家谱管理系统

一、题目&#xff1a;家谱管理系统 二、内容&#xff1a; 2.1 概述 2.1.1 选题原因 做此题的原因是因为可以比较方便的记录家族历代成员的情况与关系&#xff0c;能很好的保存家族每一代的信息&#xff0c;而不用人工纸质的方式来存取家谱&#xff0c;更便于人们保存和使用…

爬虫练习(js逆向解密)

目标 网站地址交易列表 - 福建省公共资源交易电子公共服务平台 (fj.gov.cn) 抓取内容如下&#xff1a; 分析 查找js代码 点击下一页翻页的时候&#xff0c;查看请求返回的数据&#xff0c;发现data数据是经过加密后得到的 通过全局搜索data,发现有两千多个结果&#xff0c;一个…

AI超强语音转文本SenseVoice,本地化部署教程!

文章目录 模型介绍SenseVoice在线预览链接本地化部署VsCode 远程连接 模型介绍 SenseVoice专注于高精度多语言语音识别、情感辨识和音频事件检测 多语言识别&#xff1a; 采用超过40万小时数据训练&#xff0c;支持超过50种语言&#xff0c;识别效果上优于Whisper模型。富文本…

跨境电商代购系统中前台基本功能介绍:帮助更快的了解跨境代购业务

前台多语言&#xff1a;可支持语言有中文&#xff08;繁体&#xff09;中文&#xff08;简体&#xff09;英文等。多语言使用百度翻译引擎接口实现&#xff0c;翻译效果与百度一致&#xff1b;网站语言分为两大块&#xff1a;1.系统后台有语言包可以编辑修改网站标题以及发布文…

WPS中JS宏使用说明(持续优化...)

前言 好久没发文章了&#xff0c;今天闲来无事发篇文章找找之前的码字感觉。 正文 最近在写教案&#xff0c;发现之前的技术又可以派上用场了。就是JS&#xff0c;全称JavaScript&#xff0c;这个语言太强大了&#xff0c;我发现WPS里的宏现在默认就是JS。功能选项如下图&…

MySQL数据库安装(详细)—>Mariadb的安装(day21)

该网盘链接有效期为7天&#xff0c;有需要评论区扣我&#xff1a; 通过网盘分享的文件&#xff1a;mariadb-10.3.7-winx64.msi 链接: https://pan.baidu.com/s/1-r_w3NuP8amhIEedmTkWsQ?pwd2ua7 提取码: 2ua7 1 双击打开安装软件 本次安装的是mariaDB&#xff0c;双击打开mar…