C语言实现快速排序算法

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.rhkb.cn/news/299160.html

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

相关文章

C和C++内存管理

目录&#xff1a; 一&#xff1a;C和C内存分布 二&#xff1a;C动态内存管理方式 三&#xff1a;C动态内存管理方式 四&#xff1a;operator new与operator delete函数 五&#xff1a;new和delete的实现原理 六&#xff1a;定位new表达式(placement-new) 七&#xff1…

ubuntu-server部署hive-part2-安装hadoop

参照 https://blog.csdn.net/qq_41946216/article/details/134345137 操作系统版本&#xff1a;ubuntu-server-22.04.3 虚拟机&#xff1a;virtualbox7.0 安装hadoop ​​​​​​下载上传 下载地址 https://archive.apache.org/dist/hadoop/common/hadoop-3.3.4/ 以root用…

用C/C++加Easyx实现俄罗斯方块游戏(爆肝4万字,完全免费)

前言 相信大家一定玩过俄罗斯方块这款小游戏&#xff0c;简单容易上手是老少皆宜的小游戏&#xff0c;今天大家就跟着我来实现这个小游戏吧&#xff01;让自己学的C语言有用武之地。 为了让俄罗斯方块的开发更为简单些&#xff0c;图像更为丰富&#xff0c;在这里就利用了Easyx…

设计模式总结-原型设计模式

原型设计模式 模式动机模式定义模式结构模式分析深拷贝和浅拷贝原型模式实例与解析实例一&#xff1a;邮件复制&#xff08;浅克隆&#xff09;实例二&#xff1a;邮件复制&#xff08;深克隆&#xff09; 模式动机 在面向对象系统中&#xff0c;使用原型模式来复制一个对象自…

vue使用iview导航栏Menu activeName不生效

activeName不生效 一、问题一、解决方案&#xff0c; 一、问题 根据ivew官网的提示&#xff0c;设置了active-name和open-names以后&#xff0c;发现不管是设置静态是数据还是设置动态的数据&#xff0c;都不生效 一、解决方案&#xff0c; 在设置动态名称的时候&#xff0c…

Centos7环境下安装MySQL8详细教程

1、下载mysql安装包 下载哪个版本&#xff0c;首先需要确定一下系统的glibc版本&#xff0c;使用如下命令&#xff1a; rpm -qa | grep glibc ​​​​​​​ 2、检查是否安装过mysql ps:因为以前用yum安装过&#xff0c;所以先用yum卸载。如果不是此方式或者没安装过则跳过…

基于SpringBoot Vue求职招聘系统

一、&#x1f4dd;功能介绍 基于SpringBoot Vue招聘系统的设计与实现 角色&#xff1a;管理员、企业、用户 管理员&#xff1a;管理员进入主页面&#xff0c;主要功能包括对个人中心、企业管理、用户管理、岗位类型管理、招聘信息管理、应聘记录管理、留言反馈、系统管理等进…

笛子基础入门

文章目录 1.符号2. 笛子指法说明3. 曲谱3.1 年轮3.2 生生世世爱 1.符号 笛子简谱&#xff1a;由七个基本数字组成&#xff08;1234567&#xff09;&#xff1b;高音在数字上面加一“.”&#xff0c;低音则在下面加一“.”&#xff0c;不加点则是中音&#xff1b;数字后面加横线…

Linux从入门到精通 --- 2.基本命令入门

文章目录 第二章&#xff1a;2.1 Linux的目录结构2.1.1 路径描述方式 2.2 Linux命令入门2.2.1 Linux命令基础格式2.2.2 ls命令2.2.3 ls命令的参数和选项2.2.4 ls命令选项的组合使用 2.3 目录切换相关命令2.3.1 cd切换工作目录2.3.2 pwd查看当前工作目录2.4 相对路径、绝对路径和…

基于MPPT的风力机发电系统simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1风能与风力发电机模型 4.2风力机功率特性与最大功率点 4.3 MPPT 5.完整工程文件 1.课题概述 基于MPPT的风力机发电系统simulink建模与仿真。MPPT使用S函数编写实现。基于最大功率点跟踪&#xff08…

日志服务 HarmonyOS NEXT 日志采集最佳实践

作者&#xff1a;高玉龙&#xff08;元泊&#xff09; 背景信息 随着数字化新时代的全面展开以及 5G 与物联网&#xff08;IoT&#xff09;技术的迅速普及&#xff0c;操作系统正面临前所未有的变革需求。在这个背景下&#xff0c;华为公司自主研发的鸿蒙操作系统&#xff08…

网络编程套接字应用分享【Linux C/C++ 】【UDP应用 | TCP应用 | TCP线程池小项目】

目录 前提知识 1. 理解源ip&#xff0c;目的ip和Macip 2. 端口号 3. 初识TCP&#xff0c;UDP协议 4. 网络字节序 5. socket 编程 sockaddr类型 一&#xff0c;基于udp协议编程 1. socket——创建套接字 2. bind——将套接字强绑定 3. recvfrom——接受数据 4. s…

基于jsp+Spring boot+mybatis的图书管理系统设计和实现

基于jspSpring bootmybatis的图书管理系统设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 文末获…

【精品教程】护网HVV实战教程资料合集(持续更新,共20节)

以下是资料目录&#xff0c;如需下载&#xff0c;请前往星球获取&#xff1a; 01-HW介绍.zip 02-HTTP&Burp课程资料.zip 03-信息收集_3.zip 04-SQL注入漏洞_2.zip 05-命令执行漏洞.zip 06-XSS漏洞.zip 07-CSRF.zip 08-中间件漏洞.zip 09-SSRF.zip 10-XXE.zip 11-Java反序列…

攻防世界 wife_wife

在这个 JavaScript 示例中&#xff0c;有两个对象&#xff1a;baseUser 和 user。 baseUser 对象定义如下&#xff1a; baseUser { a: 1 } 这个对象有一个属性 a&#xff0c;其值为 1&#xff0c;没有显式指定原型对象&#xff0c;因此它将默认继承 Object.prototype。 …

彩虹聚合DNS管理系统,附带系统搭建教程

聚合DNS管理系统&#xff0c;可以实现在一个网站内管理多个平台的域名解析&#xff0c;目前已支持的域名平台有&#xff1a;阿里云、腾讯云、华为云、西部数码、CloudFlare。 本系统支持多用户&#xff0c;每个用户可分配不同的域名解析权限&#xff1b;支持API接口&#xff0…

CSS设置字体样式

目录 前言&#xff1a; 1.font-family&#xff1a; 2.font-style&#xff1a; 3.font-weight&#xff1a; 4.font-size&#xff1a; 5.font-variant&#xff1a; 6.font&#xff1a; 前言&#xff1a; 在网页中字体是重要的组成部分&#xff0c;使用好字体可以让网页更…

17.应用负载压力测试

早些点&#xff0c;下午题考&#xff0c;最近几年出现的少&#xff1b; 备考较为简单&#xff1b;历年真题相似度高&#xff1b; 主要议题&#xff1a; 1.负载压力测试概述 注意这些测试细微的差别&#xff1b; 负载测试和压力测试的方法比较相似&#xff0c;但是目的不同&a…

HTML——5.表单、框架、颜色

一、表单 HTML 表单用于在网页中收集用户输入的数据&#xff0c;例如登录信息、搜索查询等。HTML 提供了一系列的表单元素&#xff0c;允许用户输入文本、选择选项、提交数据等。 <!DOCTYPE html> <html lang"en"> <head> <meta charset&q…

Git 如何去使用

目录 1. Git暂存区的使用 1.1. 暂存区的作用 1.2. 暂存区覆盖工作区&#xff08;注意&#xff1a;完全确认覆盖时使用&#xff09; 1.3. 暂存区移除文件 1.4. 练习 2. Git回退版本 2.1. 概念 2.2. 查看提交历史 2.3. 回退命令 2.4. 注意 3. Git删除文件 3.1. 需求 …