当前位置: 首页 > news >正文

【数据结构】排序——快速排序

前言

本篇博客我们继续介绍一种排序——快速排序,让我们看看快速排序是怎么实现的

💓 个人主页:小张同学zkf

⏩ 文章专栏:数据结构

若有问题 评论区见📝

🎉欢迎大家点赞👍收藏⭐文章 ​

目录

1.快速排序(hoare方法)

2.快速排序(挖坑法)

3.快速排序(前后指针法)

 4.快速排序(非递归法)

5.快速排序特性


 

1.快速排序(hoare方法)

快速排序是 Hoare 1962 年提出的一种二叉树结构的交换排序方法,其基本思想为: 任取待排序元素序列中 的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右 子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止
// 假设按照升序对 array 数组中 [left, right) 区间中的元素进行排序
void QuickSort ( int array [], int left , int right )
{
if ( right - left <= 1 )
return ;
// 按照基准值对 array 数组的 [left, right) 区间中的元素进行划分
int div = partion ( array , left , right );
// 划分成功后以 div 为边界形成了左右两部分 [left, div) [div+1, right)
// 递归排 [left, div)
QuickSort ( array , left , div );
// 递归排 [div+1, right)
QuickSort ( array , div + 1 , right );
}

 我们先看看快速排序的动图

整体思想,以左面的数据为key,然后先让right指针向右走,找比key位置上的值小的值,找到之后,停止移动,然后left指针向左移动找比key大的值,找到之后,交换left和right位置上的值,然后右指针继续找小,左指针继续找大,找到之后继续交换,重归此过程,直到左指针与右指针相遇,相遇的位置与key位置上的值交换,再把key赋值成相遇的位置。这是单趟排序。再将以key为中心分成两个左右区间再次递归到这个函数中,不断递归,直到最后的区间为1,或不存在区间。递归返回。

代码如下

但如果我们想让快排效率高,我们得考虑些极端情况,比如如果右边指针一直没找到比最左边的数大的,左右指针直接在key位置上相遇了。 递归只有一个区间一直递归,就会大大降低了快排的效率,特别是在有序的情况下,所以,只有每次递归,key都在中间位置时,效率才最快,所以我们可以定义一个三数取中的函数,函数的返回值与left位置上的值交换就ok了。

那三数取中么写,其实很简单,就是比较最左边最右边以及最中间的值,谁是第二大的,返回第二大的就行。

三数取中代码如下

int sanshuquzhong(int* a,int left, int right)
{int mid = (left + right) / 2;if (a[left] >a [mid]){if (a[mid]>a[right]){return mid;}else{if (a[right] > a[left]){return left;}else{return right;}}}else{if (a[mid] < a[right]){return mid;}else{if (a[right] > a[left]){return right;}else{return left;}}}
}

有了三数取中,快排效率就明显提高,但是还是有人觉得快排不够快,确实,随着递归的深入,效率会越来越慢,所以为了加快效率,我们可以进行小区间优化

 

我们由图分析可知最后一次递归耗费次数最多,所以我们可以对最后几次小区间下手,用其他排序替换快排,从而让效率提高,我们可以在最后几个区间时用插入排序来进行

void charupaixu(int* a, int n)
{for (int i = 0; i < n - 1; i++){int end = i;int tmp = a[end + 1];while (end >= 0){if (a[end] > tmp){a[end + 1] = a[end];end--;}else{break;}}a[end + 1] = tmp;}
}

ok,到这里我们的代码就写完了,我们想一个问题,为什么我们要选key,并且选的key在左边时,一定要右边指针先走才行,为什么这么规定那。如下图分析

 

这样快速排序(hoare方法)就初步得成,所有代码如下

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void swap(int* as, int* ak)
{int tmp = *as;*as = *ak;*ak = tmp;
}
void charupaixu(int* a, int n)
{for (int i = 0; i < n - 1; i++){int end = i;int tmp = a[end + 1];while (end >= 0){if (a[end] > tmp){a[end + 1] = a[end];end--;}else{break;}}a[end + 1] = tmp;}
}
int sanshuquzhong(int* a,int left, int right)
{int mid = (left + right) / 2;if (a[left] >a [mid]){if (a[mid]>a[right]){return mid;}else{if (a[right] > a[left]){return left;}else{return right;}}}else{if (a[mid] < a[right]){return mid;}else{if (a[right] > a[left]){return right;}else{return left;}}}
}
void kuaisupaixu(int* arr, int left,int right)
{if (right <= left){return;}if (right - left + 1 < 10)//小区间排序{charupaixu(arr + left, right -left+ 1);}int mid = sanshuquzhong(arr,left, right);//三数取中swap(&arr[mid], &arr[left]);int key = left;int begin = left;int end = right;while (begin<end){while (begin<end&&arr[end] >=arr[key]){end--;}while (begin<end&&arr[begin] <= arr[key]){begin++;}swap(&arr[end], &arr[begin]);}swap(&arr[begin], &arr[key]);key = begin;kuaisupaixu(arr,left,key-1);kuaisupaixu(arr,key+1,right);
}

 


2.快速排序(挖坑法)

随着快排的不断发展,人们优化了hoare方法,用挖坑法,虽然这种方法没有效率的提升,不过方便了人们对代码的理解再也不用考虑为什么要右边先走的问题

我们看一下这个方法的动图

 

其实就是把交换换成填补,定义一个临时变量为坑,最后把Key自然放进坑位就行,这个方法更方便我们理解

就是在hoare方法代码中微调一下就行

代码如下

// 快速排序挖坑法
void PartSort2(int* a, int left, int right)
{if (left >= right){return;}if (right - left + 1 < 10){charu(a+left, right - left + 1);}else{int mid = sanshuquzhong(a, left, right);swap(&a[mid], &a[left]);int key = a[left];int begin = left;int end = right;int keng = left;while (begin < end){while (begin < end && a[end] >= key){end--;}a[keng] = a[end];keng = end;while (begin < end && a[begin] <= key){begin++;}a[keng] = a[begin];keng = begin;}a[begin] = key;PartSort2(a, left, begin- 1);PartSort2(a, begin + 1, right);}}

3.快速排序(前后指针法)

快速排序还有另一种方法,也是最容易记住的,我们可以通过定义两个指针,刚开始一个指向key,一个指向key的下一个数,让前面那个指针一直向前走找比key小的数,第二个若找到比key小的数,那么前后指针之间的数就是比key大的数,++后指针再交换俩指针指向的数,前指针继续向前找,直到超过边界停止,最后key与此时后指针指向的书交换,并且key赋值于后指针的位置,递归key前key后空间

动图如下

我们可以画图分析一下 

 

 

代码如下

// 快速排序前后指针法
void PartSort3(int* a, int left, int right)
{if (left >= right){return;}if (right - left + 1 < 10){charu(a + left, right - left + 1);}else{int mid = sanshuquzhong(a, left, right);swap(&a[mid], &a[left]);int key = left;int man = left;int kuai = left + 1;while (kuai <= right){if (a[kuai] < a[key] && ++man != kuai){swap(&a[man], &a[kuai]);}kuai++;}swap(&a[key], &a[man]);key = man;PartSort3(a, left, key - 1);PartSort3(a, key + 1, right);}
}

 4.快速排序(非递归法)

前三种方法都是递归法,若不用递归我们该怎么弄,不用递归,我们就得需要栈这个结构,代码整体不变,把最后递归的部分改成把key左右两个区间全入栈,先右区间入栈再左区间入栈,因为栈是后进先出原则,出栈就是左区间先出栈,直到栈空,入栈的条件左指针小于Key-1,右指针大于key+1。

画图看一下

 

区间边界值入栈,来替代了递归 

代码如下

#include "stack.h"
int yici(int* a,int left,int right)
{int mid = sanshuquzhong(a, left, right);swap(&a[mid], &a[left]);int key = left;int begin = left;int end = right;while (begin < end){while (begin < end && a[end] >= a[key]){end--;}while (begin < end && a[begin] <= a[key]){begin++;}swap(&a[begin], &a[end]);}swap(&a[key], &a[begin]);key = begin;return key;
}
void QuickSortNonR(int* a, int left, int right)
{if (right - left + 1 < 10){charu(a + left, right - left + 1);}else{Stack as;StackInit(&as);StackPush(&as, right);StackPush(&as, left);while (!StackEmpty(&as)){int begin1 = StackTop(&as);StackPop(&as);int end1 = StackTop(&as);StackPop(&as);int key = yici(a, begin1, end1);if (key + 1 < end1){StackPush(&as, end1);StackPush(&as, key + 1);}if (key - 1 > begin1){StackPush(&as, key - 1);StackPush(&as, begin1);}}StackDestroy(&as);}
}

5.快速排序特性

快速排序的特性总结:
1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫 快速 排序
2. 时间复杂度: O(N*logN)

3. 空间复杂度: O(logN)
4. 稳定性:不稳定

结束语 

快排有关知识就总结完了,我认为快速排序这个排序还是蛮重要的,大家要对这个排序更加重视,最后一个排序就是归并排序了,留在下篇博客说

0K,本篇博客结束!!!

 

相关文章:

【数据结构】排序——快速排序

前言 本篇博客我们继续介绍一种排序——快速排序&#xff0c;让我们看看快速排序是怎么实现的 &#x1f493; 个人主页&#xff1a;小张同学zkf ⏩ 文章专栏&#xff1a;数据结构 若有问题 评论区见&#x1f4dd; &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐文章 ​ 目录 …...

Matlab 怎么查找矩阵中所有0的数据并赋值

index find(X40); X4(index)57.71527;...

开发一个HTTP模块

开发一个HTTP模块 HTTP模块的数据结构ngx_module_t模块的数据结构ngx_http_module_t数据结构ngx_command_s 数据结构 定义一个HTTP模块处理用户请求返回值获取URI和参数方法名URIURL协议版本 获取HTTP头获取HTTP包体 发送响应发送HTTP头发送内存中的字符串作为包体返回一个Hell…...

vue2实现复制,粘贴功能,使用vue-clipboard2插件

一、需求说明 在项目中 点击按钮 复制 某行文本是很常见的 应用场景&#xff0c; 在 Vue 项目中实现 复制功能 需要借助 vue-clipboard2 插件。 二、代码实现 1、安装 vue-clipboard2 依赖 &#xff08; 出现错误的话&#xff0c;可以试试切换成淘宝镜像源 npm config set r…...

【软件测试】 1+X初级 功能测试试题

【软件测试】 1X初级 功能测试试题 普通员工登录系统&#xff0c;在“个人信息维护”模块&#xff0c;可以查看和维护个人信息。个人信息维护需求包括用户&#xff08;UI&#xff09;页面、业务规则两部分。 UI 界面 个人信息维护 修改基本信息 业务规则 1. 个人信息维护页面…...

zynq启动和程序固化流程

普通FPGA启动 FPGA的启动方式主要包含主动模式、被动模式和JTAG模式。 主动模式&#xff08;AS模式&#xff09; 当FPGA器件上电时&#xff0c;它作为控制器从配置器件EPCS中主动发出读取数据信号&#xff0c;并将EPCS的数据读入到自身中&#xff0c;实现对FPGA的编程。这种…...

CSS3实现彩色变形爱心动画【附源码】

随着前端技术的发展&#xff0c;CSS3 为我们提供了丰富的动画效果&#xff0c;使得网页设计更加生动和有趣。今天&#xff0c;我们将探讨如何使用 CSS3 实现一个彩色变形爱心加载动画特效。这种动画不仅美观&#xff0c;而且可以应用于各种网页元素&#xff0c;比如加载指示器或…...

【JVM基础篇】Java的四种垃圾回收算法介绍

文章目录 垃圾回收算法垃圾回收算法的历史和分类垃圾回收算法的评价标准标记清除算法优缺点 复制算法优缺点 标记整理算法&#xff08;标记压缩算法&#xff09;优缺点 分代垃圾回收算法&#xff08;常用&#xff09;JVM参数设置使用Arthas查看内存分区垃圾回收执行流程分代GC算…...

Kodcloud可道云安装与一键发布上线实现远程访问详细教程

文章目录 1.前言2. Kodcloud网站搭建2.1. Kodcloud下载和安装2.2 Kodcloud网页测试 3. cpolar内网穿透的安装和注册4. 本地网页发布4.1 Cpolar云端设置4.2 Cpolar本地设置 5. 公网访问测试6.结语 1.前言 本文主要为大家介绍一款国人自研的在线Web文件管理器可道云&#xff0c;…...

python杨辉三角的两种书写方式

第一种&#xff08;设置二维列表设置每个元素为0进行替换元素&#xff09; 代码演示&#xff1a; n eval(input("请输入想要的行数")) lst[[0 for j in range(n)] for i in range(n)] # lst2[[0]*n]*n for i in range(n):for j in range(i1):if j0 or ji:lst[i][j…...

【CSS in Depth 2精译】2.5 无单位的数值与行高

当前内容所在位置 第一章 层叠、优先级与继承第二章 相对单位 2.1 相对单位的威力2.2 em 与 rem2.3 告别像素思维2.4 视口的相对单位2.5 无单位的数值与行高 ✔️2.6 自定义属性2.7 本章小结 2.5 无单位的数值与行高 有些属性允许使用无单位的数值&#xff08;unitless value…...

【人脸识别、Python实现】PyQt5人脸识别管理系统

PyQt5人脸识别管理系统 项目描述主要功能效果展示获取源码 项目描述 接的一个基于宿舍管理系统与人脸识别的小单子。然后我把它优化了一些&#xff0c;现在开源一下。有需要的小伙伴自取&#xff0c;点个免费的关注就行 主要功能 1、录入学生基本信息、录入人脸 2、主页面展…...

软设之观察者模式

设计模式中&#xff0c;观察者模式的意图是:定义对象间的一种一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都得到通知并被自动更新。 比如说&#xff0c;有一个新闻网站&#xff0c;订阅的用户众多&#xff0c;假如说管理员发布了一…...

deep learning 环境配置

1 NVIDIA驱动安装 ref link: https://blog.csdn.net/weixin_37926734/article/details/123033286 2 cuda安装 ref link: https://blog.csdn.net/qq_63379469/article/details/123319269 进去网站 https://developer.nvidia.com/cuda-toolkit-archive 选择想要安装的cuda版…...

09磁盘管理

一、磁盘管理 1.磁盘基础知识 &#xff08;1&#xff09;磁盘接口类型 个人电脑&#xff0c; 硬盘接口分为IDE类型和SATA类型 服务器版分为SCSI类型和SAS类型 &#xff08;2&#xff09;磁盘命名方式 windows中硬盘命名方式是c&#xff0c;d,e盘 linux中硬盘命名方式为 系统…...

Node.js Stream

Node.js Stream Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境&#xff0c;它允许开发者使用 JavaScript 编写服务器端代码。Node.js 的一个核心特性是其对流&#xff08;Stream&#xff09;的处理能力。流是一种在 Node.js 中处理读/写文件、网络通信或任何端到端…...

简化嵌入式Linux开发:在Ubuntu上安装和配置交叉编译环境的高效方法

在嵌入式Linux开发中&#xff0c;我们通常需要在Ubuntu上安装交叉编译工具链&#xff0c;并配置相关文件。编译过程中&#xff0c;如果遇到依赖库问题&#xff0c;还需要手动查找并编译开源源码。这些步骤较为繁琐&#xff0c;为了简化操作&#xff0c;我们可以尝试以下方案&am…...

Photoshop批量处理图片分辨率

整理一些文件的时候&#xff0c;发现需要处理大量图片的尺寸和分辨率。如果一张一张的处理就会很慢&#xff0c;搜了下&#xff0c;Photoshop提供自动批量处理的方法。在此记录一下。 一、说说批量处理图片 1.打开PS软件并导入图片&#xff0c;我用的是比较老的版本cs4&#…...

TCP协议的三次握手和四次挥手(面试)

三次握手 首先可以简单的回答&#xff1a; 1、第一次握手&#xff1a;客户端给服务器发送一个 SYN 报文。 2、第二次握手&#xff1a;服务器收到 SYN 报文之后&#xff0c;会应答一个 SYNACK 报文。 3、第三次握手&#xff1a;客户端收到 SYNACK 报文之后&#xf…...

css看见彩虹,吃定彩虹

css彩虹 .f111 {width: 200px;height: 200px;border-radius: 50%;box-shadow: 0 0 0 5px inset red, 0 0 0 10px inset orange, 0 0 0 15px inset yellow, 0 0 0 20px inset lime, 0 0 0 25px inset aqua, 0 0 0 30px inset blue, 0 0 0 35px inset magenta;clip-path: polygo…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

python报错No module named ‘tensorflow.keras‘

是由于不同版本的tensorflow下的keras所在的路径不同&#xff0c;结合所安装的tensorflow的目录结构修改from语句即可。 原语句&#xff1a; from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后&#xff1a; from tensorflow.python.keras.lay…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)

LeetCode 3309. 连接二进制表示可形成的最大数值&#xff08;中等&#xff09; 题目描述解题思路Java代码 题目描述 题目链接&#xff1a;LeetCode 3309. 连接二进制表示可形成的最大数值&#xff08;中等&#xff09; 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...

uniapp 实现腾讯云IM群文件上传下载功能

UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中&#xff0c;群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS&#xff0c;在uniapp中实现&#xff1a; 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...