排序——快速排序

目录

思想

演示

代码实现

解释

优化

三数取中

小区间优化

补充

挖坑法

双指针法

非递归实现


思想

     快速排序是一种二叉树结构的交换排序方法。

     基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

演示

     一般把序列的第一个元素认为基准值。定义两个变量一个是序列最右边一个是最左边(变量均为下标)。

09ad479c52504f9b9387557660440f67.png

     先让end走遇到比基准值小的停下来,然后让begin走遇到比基准值大的停下来,之后让它们交换位置。一直重复操作直至它们相遇。

d27f511fecf04b008ab32f3b232401f1.png

b93006cbb40f40c897e4163fe503105e.png

1e23283adf684531a2b28407657a8e81.png

d3633959a1c54bc19c5186675cd505fe.png1f609660eb054e3eaf83e280e10a886d.jpg

当它们相遇时,该位置的值一定小于基准值(在后面的解释中会有说明)。让该位置的值与基准值交换。

e928876ecbf241229a8a2d1d30d03031.png

     以上是一遍排序,还要继续排序下图的浅绿色序列和亮绿色序列,操作是和这次一样的只是范围不一样。在排完之后会继续再分用递归解决即可。

4c5f89cfdd964958aabbfc59a3e56539.png

     大概流程图如下 :

0d2a8dfee2bc4a5aac6f6aa0fe720cf9.png

     大家不能只看我画的图,也要自己画画图感受感受。

代码实现

//快速排序
void QuickSort(int* arr, int left, int right)
{if (left >= right)return;int keyi = left;int begin = left, end = right;while (begin < end){while (begin < end && arr[end] >= arr[keyi])end--;while (begin < end && arr[begin] <= arr[keyi])begin++;Swap(&arr[begin], &arr[end]);}Swap(&arr[keyi], &arr[end]);keyi = begin;QuickSort(arr, left, keyi - 1);QuickSort(arr, keyi + 1, right);
}

      Swap函数是交换两个数。

void Swap(int* p1, int* p2)
{int temp = *p1;*p1 = *p2;*p2 = temp;
}

解释

  • end遇到begin:
  1. begin没移动:那就是自己给自己交换一下位置。
  2. begin移动了:begin经历了交换它下面的值一定小于基准值。
  • begin遇到end:因为end先走,end停下的位置一定小于基准值。

     这也就解释了为什么要让end先走,如果要让begin先走那可能就不会当它们相遇时该位置的值一定小于基准值。

优化

三数取中

     快速排序的理想时间复杂度是O(NlogN),理想情况每次左右序列的长度相同时存在。如果该序列是有序或接近有序那时间复杂度就是O(N^2)如下图。这样快速排序的效率就会大打折扣。为了避免这种情况有人提出了三数取中。

c43a33fad8c54bd9b68e473bd572101a.png

     三数取中就是在序列中拿首元素,序列正中间的元素,尾元素这三个元素中挑一个中间元素来当基准值。这样做尽量保证每次的左右序列的长度相同,让它向理想情况靠近。

     当选出来时让该位置与序列首元素交换位置这么做是保证我们之前的逻辑。

//三位取中
int GetMidi(int* arr, int left, int right)
{int midi = (left + right) / 2;if (arr[left] < arr[midi]){if (arr[midi] < arr[right]){return midi;}else if (arr[left] > arr[right]){return left;}else{return right;}}else{if (arr[midi] > arr[right]){return midi;}else if (arr[left] > arr[right]){return right;}else{return left;}}
}

小区间优化

     在上面提到过快速排序是一种二叉树结构的交换排序方法。

     它是一个二叉树结构,根据二叉树特点可知最后一层开辟的空间会约占全部的50%,它的上一层约占到25%。如果数据很多那么递归调用的深度就会很深有可能造成——栈溢出。

     最后的一两层里面包含的数据并不是很多,所以我们可以写一个判断,到特定的范围内用插入排序的方式来排序(这里我写的是当数据量小于10时),这样它的深度会变小很多。

补充

挖坑法

     这是针对排一遍方法的改进下面的双指针法也是一个道理。

     将第一个数据存在一个临时变量key中,从而形成一个坑位。让end先走当遇到比key小的数据时把end位置的值放入坑中,end位置就会形成一个坑。然后让begin走遇到比key大的就把它放入坑中。一直重复操作直至它们相遇。

4737ce536ba6427ab66de936fe6880fb.png

     最后它们相遇时把key放入它们相遇位置即可。

c8f74b82d5d24ce18febf24864dd5d15.png

双指针法

     先定义两个变量一个指向序列的首元素(prev),一个指向首元素的下一位(cur)。

     如果cur对应的值大于key(序列首元素),那就让cur独自向后走。如果小于key,让prev向后走然后让cur和prev交换位置如果cur等于prev那就不需要交换位置(下图是一部分移动过程)。

c8ba9d5565414bc8aa474127e2fb80a9.png

     当cur走出序列后,让prev与key进行交换。

     prev是在cur对应的值小于key的情况下才走固prev对应的值一定小于key。

非递归实现

     快速排序的非递归实现是基于栈实现的。在递归中只有范围在不断改变,所以我们只需要在栈里存放范围即可。

     要先在栈里存入序列的最左边的下标和最右边的下标。在排序时拿出下标。排完后再向栈中压入由它分出来的两个序列的左右下标。

//快速排序
void QuickSort(int* arr, int left, int right)
{ST st;STInit(&st);//初始化栈STPush(&st, right);//入栈STPush(&st, left);while (!STEmpty(&st))//判断栈是否为空{int begin = STTop(&st);//取出栈顶元素STPop(&st);//出栈int end = STTop(&st);STPop(&st);int keyi = begin;int prev = begin, cur = prev + 1;while (cur <= right){if (arr[cur] < arr[keyi] && ++prev != cur){Swap(&arr[prev], &arr[cur]);}cur++;}Swap(&arr[keyi], &arr[prev]);if (prev + 1 < end)//当只有一个数据时没必要入栈了{STPush(&st, end);STPush(&st, prev + 1);}if (begin < prev - 1){STPush(&st, prev - 1);STPush(&st, begin);}}STDestroy(&st);//销毁栈
}

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

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

相关文章

​【数据结构与算法】冒泡排序:简单易懂的排序算法解析

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《数据结构与算法》 期待您的关注 ​ 目录 一、引言 二、冒泡排序原理 &#x1f343;基本思想&#xff1a; &#x1f343;算法…

自杀行为的神经生物学认识

自杀行为的神经生物学认识 编译 李升伟 隐藏在自杀行为背后的大脑生化机制正引领人类对自杀的认识从黑暗步入光明。科学家希望未来这些机制能带来更好的治疗和预防策略。 基斯 • 范希林根&#xff08;Cornelis Van Heeringen&#xff09;第一次遇见瓦莱丽&#xff08; Va…

大模型技术工程师:抓住时代机遇,成为行业精英_

伴随AI大模型的火热&#xff0c;中国科技大厂们正在掀起一场「跑步AI化」的风暴。从顶层战略到业务线重构&#xff0c;AI无疑已成为大厂们押注未来的新故事。 大模型时代已经到来 大模型已成为全球竞争热点&#xff0c;一个大模型时代已经到来。 大模型具备三个特点&#xf…

新手一次学会SpringBoot项目部署 + Docker中运行Samba服务设置共享目录

SpringBoot项目部署 1.IDEA打包&#xff0c;在IDEA终端&#xff0c;输入mvn clean package 2.将项目target中的jar包放入linux目录 3.运行jar包 前台运行&#xff08;直接显示输出&#xff09;&#xff1a; java -jar data-transport-server-0.0.1-SNAPSHOT.jar后台运行&…

鸿蒙开发网络管理:【@ohos.net.socket (Socket连接)】

Socket连接 说明&#xff1a; 本模块首批接口从API version 7开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 导入模块 import socket from ohos.net.socket;socket.constructUDPSocketInstance constructUDPSocketInstance(): UDPSocket 创建…

已解决:geecg Column ‘id‘ in order clause is ambiguous

报错&#xff1a;Column id in order clause is ambiguous&#xff1b; MyBatis关联查询&#xff0c;相同字段名冲突&#xff0c;sql语句已经使用别名但仍然报错。 分析&#xff1a;写mapper映射文件时&#xff0c;在写到一对一关联&#xff0c;一对多关联时&#xff0c;由于两…

从11个视角看全球Rust程序员4/4:深度解读JetBrains最新报告

讲动人的故事,写懂人的代码 8 Rust程序员最喜欢用什么工具调试程序? 用println!或dbg!宏来调试一下 2022年:55%2023年:55%在IDE里玩玩UI调试 2022年:27%2023年:29%在控制台里调试调试 2022年:11%2023年:10%不调试,任性 2022年:5%2023年:6%有其他奇思妙想 2022年:1%…

骁龙662_高通SM6115主要参数_高通模块方案定制

骁龙662&#xff08;SM6115&#xff09;采用了全新的44 Kryo 260 CPU架构&#xff0c;由四核Cortex-A73(高达2.0 GHz)和四核Cortex-A53(高达1.8 GHz)组成。这种架构的设计使得骁龙662在性能上相较于上一代产品有了显著的提升&#xff0c;为用户提供了更快的运行速度和更流畅的使…

安卓TextView控件实现下划线

效果展示 这里需要使用到LayerDrawable&#xff0c;对应于<layer-list>标签。在drawable目录下新建一个text_underline.xml文件&#xff0c;text_underline.xml的代码如下&#xff1a; <?xml version"1.0" encoding"utf-8"?> <layer-lis…

TS安装及JS转换

第一步&#xff1a;先安装好node.js&#xff0c;可以在官方下载或我们提供压缩包直接安装好node.js Node.js的官方网站是下载 | Node.js 中文网 下载对应系统的版本。我们提供是64位。安装好后调出dos命名&#xff0c;输入 npm确认下有没有安装好。 第二步&#xff1a;安装cnpm…

机器学习笔记——无监督学习下的k均值聚类

k均值聚类算法原理 目标是将样本分类 原理&#xff1a;首先随机选择k何点作为中心&#xff0c;然后计算每一个点到中心的聚类&#xff0c;然后计算到每个中心的距离&#xff0c;选择到中心最短距离的那个中心所在的类进行归类&#xff0c;然后更新中心点&#xff0c;一直重复。…

vivado PKGPIN_NIBBLE

描述 PKGPIN_NIBBLE是PKGPIN_BYTEGROUP的一部分。参见PKGPIN_BYTEGROUP&#xff0c; 第122页了解该对象的描述。 相关对象 PKGPIN_BYTEGROUP和PKGPIN_NIBBLE与IO_BANK、PACKAGE_PIN和 PORT&#xff0c;如前所述。此外&#xff0c;每个PKGPIN_NIBBLE都与 Xilinx设备。您可以使用…

【触想智能】工业显示器定制时需要注意的重点问题

随着工业自动化的不断发展&#xff0c;工业显示器越来越重要。不同于普通的娱乐和商业应用&#xff0c;工业显示器需要更加耐用、可靠、安全&#xff0c;并且满足特定的工业环境和应用需求。 因此&#xff0c;仔细考虑和选择适合自己的工业显示器至关重要。本文将介绍一些您在进…

React 中的 ErrorBoundary

在 React 中&#xff0c;如果不做任何控制&#xff0c;当组件出现异常时&#xff0c;React 渲染就会停止&#xff0c;页面出现白屏&#xff0c;这种体验很不好。例如当用户输入某些非法数据&#xff0c;而前端都没有进行校验&#xff0c;页面出现白屏。这种情况下&#xff0c;最…

CUDA C权威编程指南 第4章 全局内存

一、CUDA内存模型概述 1. CUDA内存模型 对于程序员来说&#xff0c;一般有两种类型的存储器&#xff1a; 可编程的&#xff1a;你需要显式地控制哪些数据存放在可编程内存中 不可编程的&#xff1a;你不能决定数据的存放位置&#xff0c;程序将自动生成存放位置以获得良好…

基于SpringBoot+Vue会所产后护理系统设计和实现

基于SpringBootVue会所产后护理系统设计和实现 &#x1f345; 作者主页 网顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承接各种定制系统 &#…

179海关接口源码,跨境报关商城+多平台搭建+多终端支持

在跨境贸易中&#xff0c;报关是一个非常重要的环节。而179海关接口源码提供了一种方便快捷的方式来实现跨境报关的功能。它还支持多平台搭建和多终端支持&#xff0c;让整个报关流程更加高效和便捷。 1. 179海关接口源码的功能 179海关接口源码提供了多种功能&#xff0c;其…

Gradle 自动化项目构建-Gradle 核心之 Project

一、前言 从明面上看&#xff0c;Gradle 是一款强大的构建工具&#xff0c;但 Gradle 不仅仅是一款强大的构建工具&#xff0c;它更像是一个编程框架。Gradle 的组成可以细分为如下三个方面&#xff1a; groovy 核心语法&#xff1a;包括 groovy 基本语法、闭包、数据结构、面…

基于Java的二手手机回收平台系统

开头语&#xff1a; 你好呀&#xff0c;我是计算机学长猫哥&#xff01;如果有相关需求&#xff0c;文末可以找到我的联系方式。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;JavaJSPServlet 工具&#xff1a;IDEA/Eclipse、Navicat、Maven 系统展…

257、二叉树的所有路径

给定一个二叉树&#xff0c;返回所有从根节点到叶子节点的路径。 说明: 叶子节点是指没有子节点的节点。 代码如下&#xff1a; class Solution { public:void traversal(TreeNode* cur, vector<int>& path, vector<string> &result){path.push_back(cur…