C语言实现快速排序算法

news2025/1/16 17:59:28

1. 什么是快速排序算法

快速排序的核心思想是通过分治法(Divide and Conquer)来实现排序。

算法的基本步骤是:

1. 选择一个基准值(通常是数组中的某个元素),将数组分成两部分,使得左边的部分所有元素都小于基准值,右边的部分所有元素都大于基准值。

2. 对这两部分分别进行递归排序,直到整个数组有序。

那么,该算法为什么叫做快速排序算法呢?

快速排序算法之所以被称为“快速”,是因为它在大多数情况下都能够快速地完成排序。在平均情况下,其时间复杂度为O(nlogn),其中n为数组的大小。

此外,快速排序还具有原地排序的特点,即不需要额外的辅助空间,只需对原始数组进行原地操作。这些优点使得快速排序成为了排序问题中的一种首选算法。


2. 单趟排序

单趟排序指的就是将数组分为两部分的算法。

对于实现这一步,我们有三种思路。

2.1 霍尔法

霍尔并无什么特殊含义,只是因为最早发现快速排序算法的人叫霍尔,这是他的实现方法。

思路:

1. 先选定一个基准值key(一般选择首元素)。

2. 定义两个指针left和right,分别指向数组的左右两端。

3. left从左往右遍历,寻找大于基准值的元素,right从右往左遍历,寻找小于基准值的元素。

4. 如果left与right未相遇,那么就交换两指针指向的元素。

5. 如果left与right相遇,那么就让key指向的元素与right指向的元素交换。

代码

//霍尔法
int ParSort_1(int* arr, int left, int right)
{
    int key = left;
    while (left < right)
    {
        while (left < right && arr[right] >= arr[key]) { right--; }
        while (left < right && arr[left] <= arr[key]) { left++; }
        if (left < right)
            swap(&arr[left], &arr[right]);
    }

    swap(&arr[key], &arr[left]);
    return left;
}

注意事项(如何保证right和left共同指向的元素与key指向的元素交换是合理的)

1. 如果选取的基准值为首元素,那么在外层循环的一次循环中,一定要让right先进行移动,这样可以确保共同指向的元素是小于或等于基准值的。

2. 如果选取的基准值为最后一个元素,则与上面相反。

2.2 挖坑法

核心思想与霍尔法相同,但是表现形式有所差异。

思路

顾名思义,我们将基准值单独用变量进行存放,而将基准值原本所在的位置空出来成为一个坑(我们将其称作hole)。

1. right先进行遍历,如果发现有小于基准值的元素,则将该元素填入hole中,然后right指向的位置成为新的hole。(假设F小于key)

2. 然后left再进行遍历,如果发现有大于基准值的元素,则将该元素填入hole中,然后left指向的位置成为新的hole。(假设B大于key)

 3. 以此类推,当left与right相遇时,将key填入hole中即可。

代码

//挖坑法
int ParSort_2(int* arr, int left, int right)
{
    int key = arr[left];
    int hole = left;

    while (left < right)
    {
        while (left < right && arr[right] >= key) { right--; }
        arr[hole] = arr[right];
        hole = right;

        while (left < right && arr[left] <= key) { left++; }
        arr[hole] = arr[left];
        hole = left;
    }

    arr[hole] = key;
    return hole;
}

注意事项

对于这个方法来说,洞在谁那边,谁就先开始遍历。

2.3 前后指针法

思路

1. 定义两个指针,prev和cur,prev所指向的以及之前的元素就是小于基准值的元素,cur用于遍历数组。

2. 如果cur找到小于基准值的元素,让prev++,然后交换prev指向的元素和cur指向的元素。

3. 让基准值与prev指向的元素进行交换。

代码

//前后指针
int ParSort_3(int* arr, int left, int right)
{
    int key = left;
    int prev = left;
    int cur = left + 1;
    while (cur <= right)
    {
        //arr[cur]小于基准值就交换
        if (arr[cur] <= arr[key] && ++prev != cur)
        {
            swap(&arr[prev], &arr[cur]);
        }
        cur++;
    }

    swap(&arr[key], &arr[prev]);
    return prev;
}

注意事项

如果选取的基准值为首元素,则在最后让prev指向的元素与基准值交换;如果选区的基准值为最后一个元素,则在最后让prev指向的下一个元素与基准值交换。

3. 快速排序算法的递归实现

按照第一部分的介绍,我们很容易的到下面的代码。

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

    int key = ParSort_3(arr, begin, end);
    QuickSort(arr, key + 1, end);//排右边
    QuickSort(arr, begin, key - 1);//排左边
}

4. 快速排序算法的优化

当数据量十分巨大时,使用递归实现的快速排序算法会由于调用函数次数过多而导致程序效率下降。

由于递归的逻辑结构像是一个树状图,所以在递归的层次较深时,每次进到下一层都会调用上一层两倍数量的函数。

众所周知,2^{n}是一个极其可怕的东西,那么我们能不能在层次较深,所需排序的数组长度较短时,转而使用其他经典的排序算法呢?

于是我们做出了如下的优化:

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

    if (end - begin <= 8)
    {
        InsertSort(arr + begin, end - begin + 1);
        return;
    }

    int key = ParSort_3(arr, begin, end);
    QuickSort(arr, key + 1, end);//排右边
    QuickSort(arr, begin, key - 1);//排左边
}

当数组长度小于等于9时,我们采用插入排序来进行排序(不止插入排序,其他排序也可)。

//插入排序
void InsertSort(int* arr, int len)
{
	for (int i = 1; i < len; i++)
	{
		int j = i;
		while (j > 0 && arr[j] < arr[j - 1])
		{
			swap(&arr[j], &arr[j - 1]);
			j--;
		}
	}
}

5. 结语

快速排序的非递归算法是用栈模拟递归实现的,由于太麻烦我就没写,感兴趣可以自己尝试写写。

单趟排序算法用哪个,快速排序递归还是非递归,层次较深时换用什么排序算法,这些都是可以自由组合的。

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

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

相关文章

文心一言指令词宝典之营销文案篇

作者&#xff1a;哈哥撩编程&#xff08;视频号、抖音、公众号同名&#xff09; 新星计划全栈领域优秀创作者博客专家全国博客之星第四名超级个体COC上海社区主理人特约讲师谷歌亚马逊演讲嘉宾科技博主极星会首批签约作者 &#x1f3c6; 推荐专栏&#xff1a; &#x1f3c5;…

Linux:IO多路转接之poll

文章目录 select的缺点pollstruct pollfd解决缺点的方式 代码实现 本篇总结的是poll的相关内容&#xff0c;在总结poll的内容前&#xff0c;先回顾一下select的缺点 select的缺点 select的缺点也比较明显 等待的fd是有上限的&#xff0c;在我们当前这个版本来说&#xff0c;…

Hive 之 UDF 运用(包会的)

文章目录 UDF 是什么&#xff1f;reflect静态方法调用实例方法调用 自定义 UDF&#xff08;GenericUDF&#xff09;1.创建项目2.创建类继承 UDF3.数据类型判断4.编写业务逻辑5.定义函数描述信息6.打包与上传7.注册 UDF 函数并测试返回复杂的数据类型 UDF 是什么&#xff1f; H…

【Redis教程0x0F】Redis实战篇

Redis如何实现延迟队列&#xff1f; 延迟队列是指把当前要做的事情&#xff0c;往后推迟一段时间再做。延迟队列的常见使用场景有以下几种&#xff1a; 在淘宝、京东等购物平台上下单&#xff0c;超过一定时间未付款&#xff0c;订单会自动取消&#xff1b;打车的时候&#x…

Android中的aidl接口及案例说明

目录 一、什么是AIDL 二、AIDL语法规格 三、AIDL实例 客户端: 服务端: 一、什么是AIDL AIDL,即 Android Interface Definition Language,用于android不同进程间通信接口。同一个应用里面还是建议用正常接口实现功能即可。 官方说明:Android 接口定义语言 (AIDL) | …

150行Python代码模拟太阳系行星运转

今天我们用Python来模拟一下太阳系行星运动轨迹~ 先上成品图&#xff08;运行效果含音乐的呦&#xff09; 想要实现这样的效果并不难 准备材料 首先我们需要准备这样一些材料 宇宙背景图 背景透明的行星图 编写代码 代码分块详解 导入需要的模块 import pygame import …

高效学习方法:冥想背诵,看一句念一句,再每个词分析位置及语法等合理性,忘记哪个词再看猜下为什么会忘,跟自己的表达哪里不一样。

原则&#xff1a;易学则易行&#xff0c;则效果最好。《易经》 你提到的这种学习方法结合了多种记忆和理解技巧&#xff0c;可以帮助提高学习效率。下面是对这种方法的一个详细解释和一些建议&#xff1a; 冥想背诵&#xff1a;通过冥想来集中注意力&#xff0c;可以帮助你在没…

redis 数据库的安装及使用方法

目录 一 关系数据库与非关系型数据库 &#xff08;一&#xff09;关系型数据库 1&#xff0c;关系型数据库是什么 2&#xff0c;主流的关系型数据库有哪些 3&#xff0c;关系型数据库注意事项 &#xff08;二&#xff09;非关系型数据库 1&#xff0c;非关系型数据库是…

WLAN组网经典实验

1、项目需求 现有一无线网络建设,需求为三层组网,AP、STA网关均在核心交换机上,AC作为给AP分配IP地址的DHCP,SW1作为给STA分配IP地址的DHCP,默认AP工作在vlan1上,说白了就是管理vlan流量在AC上跑,业务vlan流量在核心上跑。 2、项目规划 如上图所示: AP1管理vlan: 2 …

Unity性能优化篇(十四) 其他优化细节以及UPR优化分析器

代码优化&#xff1a; 1. 使用AssetBundle作为资源加载方案。 而且经常一起使用的资源可以打在同一个AssetBundle包中。尽量避免同一个资源被打包进多个AB包中。压缩方式尽量使用LZ4&#xff0c;少用或不要用LZMA的压缩方式。如果确定后续开发不会升级Unity版本&#xff0c;则可…

基于SpringBoot+Vue的前后端分离的电影院售票管理运营平台

一、项目背景介绍&#xff1a; 该系统研究背景聚焦于电影市场的快速增长、互联网电影院管理、用户体验和服务优化以及数据管理与决策支持。随着人们生活水平的提高&#xff0c;电影观影已成为重要的娱乐方式&#xff0c;电影院作为传统场所面临新的挑战。借助SpringBootVue技术…

vscode的源码插件GitHub Repositories

打铁还需自身硬&#xff0c;需要不断提升自我&#xff0c;提升自我的一种方式就是看源码&#xff0c;站在更高的维度去理解底层原理&#xff0c;以便以后更好的开发和解决问题&#xff0c;由于源码一个动不动就是几个G甚至十几个G&#xff0c;如果一个个源码下载下来&#xff0…

NLP在搜索召回领域中的应用场景

自然语言处理&#xff08;NLP&#xff09;在搜索召回领域中的应用场景非常广泛&#xff0c;它通过理解和分析人类语言&#xff0c;提高了信息检索的准确性和效率。以下是一些具体的应用场景&#xff1a; 1. 搜索引擎优化 NLP技术可以用于优化搜索引擎的查询处理&#xff0c;通…

江协科技STM32:TIM输出比较

输出比较模块的主要功能&#xff1a;输出一定频率和占空比的PWM波形 CC是捕获比较的意思,R是Register&#xff0c;寄存器的意思&#xff0c;CCR捕获比较寄存器它是输入捕获和输出比较共用的 当使用输入捕获&#xff0c;它就是捕获寄存器 当使用输出比较&#xff0c;它就是比…

分享webgl魔幻星球

界面截图 webgl 是在网页上绘制和渲染三维图形的技术&#xff0c;可以让用户与其进行交互。divcss、canvas 2d 专注于二维图形。 对公司而言&#xff0c;webgl 可以解决他们在三维模型的显示和交互上的问题&#xff1b;对开发者而言&#xff0c;webgl 可以让我们是实现更多、更…

大学教材《C语言程序设计》(浙大版)课后习题解析 | 第十一、十二章

概述 本文主要提供《C语言程序设计》(浙大版) 第十一、十二章的课后习题解析&#xff0c;以方便同学们完成题目后作为参考对照。 专栏直达链接&#xff1a; 《C语言程序设计》(浙大版)_孟俊宇-MJY的博客-CSDN博客​http://t.csdnimg.cn/ZtcgY 一.第十一章&#xff08;指针进…

【第十五篇】使用BurpSuite实现IDOR越权(实战案例)

程序不存在严格的访问控制&#xff0c;从而实现未授权访问等。 如图&#xff0c;用户 ID 用于检索相关用户的数据&#xff0c;以呈现帐户页面。 思路&#xff1a;进行爆破或修改请求后发包&#xff0c;查看是否存在IDOR越权 操作&#xff1a;遍历ID参数&#xff0c;查看回显 …

VMware配置环境(安装运行问题)及系列dns端口网络类型IP远程连接学习之(详谈8000字)

安装vmware快速配置步骤 下载VMware安装包 在下载好VMware安装包之后双击运行 接受条款 关闭VMware自动更新 勾选快捷键方式 安装VMware安装 输入许可证&#xff08;有需要私信小编&#xff09; 安装完成 重启电脑即可 最终成功界面: 安装Linux系统 创建虚拟机 选择…

0基础没编程经验能学嵌入式吗?

0基础没编程经验能学嵌入式吗&#xff1f; 可以的&#xff0c;即使你是0基础&#xff0c;没有编程经验&#xff0c;也完全有可能学习嵌入式系统。嵌入式系统是计算机技术与特定应用领域相结合的产物&#xff0c;涉及硬件和软件的知识。从零开始学习嵌入式开发&#xff0c;你可…

MySQL-用户与权限管理:用户管理、权限管理、角色管理

用户与权限管理 用户与权限管理1.用户管理1.1 登录MySQL服务器1.2 创建用户1.3 修改用户1.4 删除用户1.5 设置当前用户密码1.6 修改其它用户密码 2. 权限管理2.1 权限列表2.2 授予权限的原则2.3 授予权限2.4 查看权限2.5 收回权限 访问控制连接核实阶段请求核实阶段 3. 角色管理…