深入理解C语言数据结构之快速排序三路划分

在数据结构和算法的世界里,排序算法是基石一般的存在。快速排序作为一种高效的排序算法,以其平均情况下的优秀时间复杂度而被广泛应用。今天,让我们深入探讨快速排序的一种变体——三路划分的快速排序,看看它是如何在C语言中施展魔法的。
 


快速排序基础回顾
 


在介绍三路划分快速排序之前,先来简单回顾下传统快速排序。传统快速排序的核心思想是分治法,选择一个基准元素,通过一趟排序将待排序列分割成两部分,其中一部分的元素都比基准元素小,另一部分的元素都比基准元素大,然后分别对这两部分递归地进行排序。
 
传统快速排序代码示例
 

c#include <stdio.h>// 交换两个整数
void swap(int *a, int *b) {int temp = *a;*a = *b;*b = temp;
}// 划分函数
int partition(int arr[], int low, int high) {int pivot = arr[high];int i = (low - 1);for (int j = low; j <= high - 1; j++) {if (arr[j] < pivot) {i++;swap(&arr[i], &arr[j]);}}swap(&arr[i + 1], &arr[high]);return (i + 1);
}// 快速排序函数
void quickSort(int arr[], int low, int high) {if (low < high) {int pi = partition(arr, low, high);quickSort(arr, low, pi - 1);quickSort(arr, pi + 1, high);}
}// 打印数组
void printArray(int arr[], int size) {for (int i = 0; i < size; i++)printf("%d ", arr[i]);printf("\n");
}


 
 
可以使用以下方式调用这个函数:
 

cint main() {int arr[] = {10, 7, 8, 9, 1, 5};int n = sizeof(arr) / sizeof(arr[0]);printf("初始数组: ");printArray(arr, n);quickSort(arr, 0, n - 1);printf("排序后的数组: ");printArray(arr, n);return 0;
}


 
 
在传统快速排序中,每次划分只能确定一个基准元素的最终位置,当数组中存在大量重复元素时,这种方式的效率会受到影响。而三路划分快速排序就是为了解决这个问题而诞生的。
 


三路划分快速排序原理
 


三路划分快速排序,也称为荷兰国旗问题的解法(因为它和将红、白、蓝三种颜色的球按顺序排列的问题类似)。在三路划分中,数组被分成三个部分:小于基准元素的部分、等于基准元素的部分和大于基准元素的部分。
 
具体步骤
 
1. 初始化指针:设置三个指针, lt (less than)初始指向数组起始位置, gt (greater than)初始指向数组末尾位置, i  初始也指向数组起始位置。
 
2. 遍历数组:通过  i  指针遍历数组:
 
- 如果  arr[i]  小于基准元素,交换  arr[i]  和  arr[lt] ,然后  i  和  lt  都向右移动一位。
 
- 如果  arr[i]  等于基准元素, i  直接向右移动一位。
 
- 如果  arr[i]  大于基准元素,交换  arr[i]  和  arr[gt] ,然后  gt  向左移动一位,但  i  不移动,因为交换过来的  arr[gt]  还未比较。
 
3. 递归排序:递归地对小于基准和大于基准的两部分进行排序。
 
三路划分快速排序代码实现
 

c#include <stdio.h>// 交换两个整数
void swap(int *a, int *b) {int temp = *a;*a = *b;*b = temp;
}// 三路划分函数
void partition(int arr[], int low, int high, int *lt, int *gt) {int pivot = arr[low];*lt = low;*gt = high;int i = low;while (i <= *gt) {if (arr[i] < pivot) {swap(&arr[*lt], &arr[i]);(*lt)++;i++;} else if (arr[i] > pivot) {swap(&arr[i], &arr[*gt]);(*gt)--;} else {i++;}}
}// 三路划分快速排序函数
void quickSort3Way(int arr[], int low, int high) {if (low < high) {int lt, gt;partition(arr, low, high, &lt, &gt);quickSort3Way(arr, low, lt - 1);quickSort3Way(arr, gt + 1, high);}
}// 打印数组
void printArray(int arr[], int size) {for (int i = 0; i < size; i++)printf("%d ", arr[i]);printf("\n");
}


 
可以使用以下方式调用这个函数:
 

cint main() {int arr[] = {10, 7, 8, 9, 1, 5, 5, 5};int n = sizeof(arr) / sizeof(arr[0]);printf("初始数组: ");printArray(arr, n);quickSort3Way(arr, 0, n - 1);printf("排序后的数组: ");printArray(arr, n);return 0;
}


注意点和要点
 
1. 基准元素的选择:在上述代码中,我们选择数组的第一个元素作为基准元素。在实际应用中,也可以随机选择基准元素,以避免最坏情况的发生。
 
2. 边界条件:在划分过程中,要注意指针的移动和边界条件的判断,确保不会越界。
 
3. 递归终止条件:递归调用时,要确保递归有终止条件,即  low < high ,否则会导致栈溢出。
 
4. 性能优势:三路划分快速排序在处理包含大量重复元素的数组时,性能明显优于传统快速排序,因为它避免了对重复元素的重复排序。
 


总结
 


三路划分快速排序是一种在特定情况下表现出色的排序算法,通过巧妙的指针操作和划分策略,它有效地提高了对包含重复元素数组的排序效率。希望通过这篇博客,你对三路划分快速排序有了更深入的理解,并且能够在实际应用中灵活运用。在算法的世界里,每一次的探索都像是一场奇妙的冒险,愿你在这个充满挑战和惊喜的领域中不断前行。

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

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

相关文章

Java实现后量子密码(PQC)与国密算法(SM4)混合加密

以下是使用Java实现一种后量子密码(PQC)与国密算法(SM4)混合加密的示例方案。该方案结合了后量子密码的抗量子特性与国密算法的国产化合规要求,适合需要双重安全保障的场景。 一 . 方案验证 1.代码截图 2.运行测试 二 . 方案设计 密钥交换:使用后量子密码(如Kyber)生…

【SQL Server数据库备份详细教程】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

SpringBoot古典舞在线交流平台设计与实现

随着古典舞文化的普及&#xff0c;越来越多的人希望通过线上平台交流学习。幽络源作为一站式综合平台&#xff0c;致力于为用户提供免费源码、技术教程及网络兼职资源。本文将详细介绍基于SpringBoot的古典舞在线交流平台的设计与实现&#xff0c;帮助开发者快速搭建一个功能完…

关于绝对时间、人类时间、本地时间、时区时间的对比分析,结合编程场景(如Java)进行说明

以下是关于绝对时间、人类时间、本地时间、时区时间的对比分析&#xff0c;结合编程场景&#xff08;如Java&#xff09;进行说明&#xff1a; 1. 定义与核心区别 (1) 绝对时间&#xff08;Absolute Time&#xff09; 定义&#xff1a;不受时区影响&#xff0c;以固定时间起点…

go语言中的strings库

strings库 func EqualFold func EqualFold(s, t string) bool判断两个utf-8编码字符串&#xff08;将unicode大写、小写、标题三种格式字符视为相同&#xff09;是否相同。 func main() {fmt.Println(strings.EqualFold("hello", "hello")) //truefmt.…

Git冲突解决

目录 一、Git冲突产生的原因二、解决Git冲突的步骤1. 发现冲突2. 查看冲突文件3. 手动解决冲突4. 提交解决后的代码5. 完成合并 三、预防Git冲突的小技巧四、总结 在团队协作开发中&#xff0c;Git冲突是常见的问题。当多个开发者同时修改了同一个文件的不同部分&#xff0c;然…

Spring AOP + RocketMQ 实现企业级操作日志异步采集(实战全流程)

Spring AOP + RocketMQ 实现企业级操作日志异步采集(实战全流程) 📌 项目背景 在企业级微服务架构中,记录操作日志是一项刚需。传统方式常使用数据库直接写入或通过 Feign 调用日志微服务,但这样存在耦合高、主流程阻塞、扩展性差等问题。 为此,我们将使用: Spring …

Git Flow 分支管理策略

优势 清晰的分支结构&#xff1a;每个分支都有明确的用途&#xff0c;便于团队协作。 稳定的 master 分支&#xff1a;生产环境代码始终稳定。 灵活的发布管理&#xff1a;通过发布分支和热修复分支&#xff0c;可以灵活管理版本发布和紧急修复。 主要分支 master 分支 代表…

Altium Designer数模电学习笔记

模电 电容 **退耦&#xff1a;**利用通交阻直&#xff0c;将看似直流的信号中的交流成分滤除 &#xff08;一般用在给MPU供电&#xff0c;尽量小一些&#xff0c;10nf~100nf~1uf以下&#xff09; **滤波&#xff1a;**也可以理解为给电容充电&#xff0c;让电容在电平为低时…

光谱仪与光谱相机的核心区别与协同应用

一、核心功能与数据维度 ‌光谱仪‌ ‌功能定位‌&#xff1a;专注单点或线状区域的光谱分析&#xff0c;通过色散元件&#xff08;光栅/棱镜&#xff09;分离波长&#xff0c;生成一维或二维光谱曲线&#xff0c;用于量化光强、吸收率等参数‌。 ‌数据维度‌&#xff1a;输…

Pytorch中layernorm实现详解

平时我们在编写神经网络时&#xff0c;经常会用到layernorm这个函数来加快网络的收敛速度。那layernorm到底在哪个维度上进行归一化的呢&#xff1f; 一、问题描述 首先借用知乎上的一张图&#xff0c;原文写的也非常好&#xff0c;大家有空可以去阅读一下&#xff0c;链接放…

linux--时区查看和修改

查看当前时间和时区: 打开终端&#xff0c;输入以下命令查看当前的日期和时间设置&#xff1a; timedatectl修改时区: 使用 timedatectl 命令来修改时区&#xff1a; sudo timedatectl set-timezone <时区>例如&#xff0c;设置时区为北京时间&#xff08;中国标准时间&a…

在windows下安装windows+Ubuntu16.04双系统(上)

这篇文章的内容主要来源于这篇文章&#xff0c;给文章很详细的介绍了如何从windows下安装windowsubuntu16.04双系统。我刚开始装双系统都是参照这个方法&#xff0c;该作者前后更新了两个版本&#xff0c;在这里对其稍微进行整理一下。 一、准备&#xff1a;&#xff08;这里推…

如何获取thinkphp的所有发行版本

是的&#xff0c;你只需要一行代码 composer show topthink/think --all 然后做了一个小实验&#xff0c;神奇的事情发生了。是我眼睛花了吗&#xff1f; 命令也能模糊查询了吗&#xff1f;tp6也太。。。。

算法模型从入门到起飞系列——递归(探索自我重复的奇妙之旅)

文章目录 前言一、递归本质1.1 递归的要素1.2 递归特点 二、递归&迭代2.1 递归&迭代比较2.2 递归&迭代如何实现相同功能2.2.1 递归实现2.2.2 迭代实现2.2.3 性能对比 三、优雅的递归理解3.1 阶乘计算分解3.2 [DFS](https://blog.csdn.net/qq_38315952/article/deta…

Android 系统进程启动Activity方法说明

前面文章Android Activity的启动器ActivityStarter入口说到Activity的恢复执行是由 mRootWindowContainer.resumeFocusedTasksTopActivities(mTargetRootTask, mStartActivity, mOptions, mTransientLaunch)来实现的&#xff0c;下面就看下它的实现。 RootWindowContainer类的…

PostgreSQL_安装

目录 前置&#xff1a; 安装过程&#xff1a; 1 下载软件 2 创建安装文件夹和放置数据的文件夹 3 双击安装 4 连接服务 前置&#xff1a; PostgreSQL 15 windows 10 专业版 安装过程&#xff1a; 1 下载软件 PostgreSQL: Downloads 大小326MB 2 创建安装文件夹和放…

docker desktop 集成WSL Ubuntu22.04

Windows docker desktop 设置WSL ubuntu 22.04启用与其他发行版的集成 Windows docker desktop 安装参考 wsl ubuntu 22.04 查看我宿主机的docker desktop 容器全部的信息 wsl -d Ubuntu-22.04 -u root

从国家能源到浙江交通投资,全息技术在能源交通领域的创新应用

一、3D全息技术行业应用参数及设计制作要求 全息投影 全息投影技术通过激光器、全息片等设备&#xff0c;将物体的三维信息记录下来&#xff0c;并在特定条件下再现。应用参数包括投影距离、投影面积、投影亮度等。设计制作要求&#xff1a;高清晰度、高亮度、低噪音、稳定性好…

新能源汽车充换站如何实现光储充一体化管理?

长三角某换电站光伏板晒到发烫&#xff0c;却因电网限电被迫切机&#xff1b;北京五环充电站每月多缴6万超容费&#xff1b;深圳物流车充电高峰排队3小时...当95%的充换站深陷“用不起绿电、扛不住扩容、算不清碳账”困局&#xff0c;安科瑞用一组真实数据撕开行业潜规则&#…