【数据结构】快速排序(详解)

目录

快速排序

历史:

基本思想:

主框架:

下面解释实现单次排序的几种版本:

1.Hoare版本

2. 挖坑法

3. 前后指针法

快速排序的实现包括递归与非递归:

1. 递归实现:(即开头的基本框架)

2. 非递归:(迭代)

下面我们通过栈来演示非递归实现快速排序:


快速排序

历史:

快速排序是Hoare(霍尔)于1962年提出的一种二叉树结构的交换排序方法

基本思想:

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

主框架:

上述为快速排序递归实现的主框架,我们可以发现它和二叉树的前序遍历十分相似 

下面解释实现单次排序的几种版本:
1.Hoare版本

单趟动图演示:

步骤:

  1. 选择基准值:通常选择序列的第一个元素或最后一个元素作为基准值。

  2. 设置两个int变量记录数组下标:一个记录序列的开始的下标(left),另一个记录序列的末尾的下标(right)。

  3. 开始分区

    • 先让right++,直到找到一个比基准值大的元素。
    • 再让left--,直到找到一个比基准值小的元素。
    • 交换这两个元素的位置,并继续right++。
    • 重复上述步骤,直到left >= right。
    • 注意:right先加,保证下一步骤与基准值交换的值小于基准值
  4. 交换基准值与right位置的值:此时,基准值左边的所有元素都比基准值小,基准值右边的所有元素都比基准值大。

代码实现:

int PartSort1(int* a, int left, int right) {int key = left;while (left < right) {while(a[right] >= a[key]&&left < right) {right--;}while(a[left] <= a[key]&&left < right) {left++;}swap(&a[left], &a[right]);}swap(&a[key], &a[right]);return left;
}
2. 挖坑法

单趟动图演示:

步骤:

  1. 选择基准元素:在待排序的序列中,选择一个元素作为基准元素(key)。这个元素可以是序列的第一个元素、最后一个元素或者任意一个元素,甚至是随机选取的一个元素。

  2. 挖坑:将基准元素从原位置移除,形成一个“坑”(hole)。

  3. 填坑:从序列的一端开始(可以是左端或右端),将遇到的第一个比基准元素小(或大)的元素填入坑中,并形成一个新的坑。这里有两种情况:

    • 如果从右向左遍历,遇到比基准元素小的元素,则将其填入坑中,并继续从左向右遍历。这里代码实现选择该情况
    • 如果从左向右遍历,遇到比基准元素大的元素,则将其填入坑中,并继续从右向左遍历。
  4. 此时,基准元素左边的所有元素都小于基准元素,右边的所有元素都大于或等于基准元素。

代码实现:

int PartSort2(int* a, int left, int right) {int x = a[left];int key = left;while (left < right) {while (a[right] >= x && left < right) {right--;}a[key] = a[right];key = right;while (a[left] <= x && left < right) {left++;}a[key] = a[left];key = left;}a[key] = x;return key;
}
3. 前后指针法

单趟动图演示:

基本步骤:

  • 从待排序的数组中选择一个元素(key)作为基准。通常选择第一个或最后一个元素作为基准,但也可以随机选择。
  • 设置两个下标,一个记录序列的开始的下标(pre),即pre=left,另一个记录pre下一个元素的下标的下标(cur),即cur=pre+1;
  • 当(cur<=right)时,循环执行:cur找比key小的元素,如果a[cur]<=a[key],交换a[cur]和a[pre],否则pre++,每次循环cur++

代码实现:

int PartSort3(int* a, int left, int right) {int key = left;int pre = left;int cur = pre + 1;while (cur <= right) {if (a[cur] <= a[key] && ++pre != cur) {swap(&a[cur], &a[pre]);}cur++;}swap(&a[key], &a[pre]);return pre;
}
快速排序的实现包括递归与非递归:
1. 递归实现:(即开头的基本框架)
void QuickSort(int* a, int left, int right) {if (left >= right) {return;}//int key = PartSort1(a, left, right);//int key = PartSort2(a, left, right);int key = PartSort3(a, left, right);QuickSort(a, left, key - 1);QuickSort(a, key + 1, right);
}
2. 非递归:(迭代)

在非递归版本中,我们使用栈(或队列)来保存待排序的子数组的起始和结束索引,而不是直接递归调用;栈相当于前序遍历,而队列相当于层序遍历

下面我们通过栈来演示非递归实现快速排序:

思路与步骤:

  1. 循环处理栈:当栈不为空时,执行以下步骤:

  • 弹出栈顶的两个元素,它们分别表示当前子数组的起始和结束索引。
  • 如果起始索引等于结束索引(即子数组只有一个元素),那么直接跳过,不需要排序。
  • 调用PartSort3函数对当前子数组进行划分,并返回划分后的基准索引key
  • 弹出之前压入的起始和结束索引(因为已经处理过这个子数组了)。
  • 根据key的位置,决定下一步的操作:
    • 如果key等于起始索引left,说明基准左边的元素都已经排好序,只需要对基准右边的元素进行排序,所以将key + 1right压入栈中。
    • 如果key等于结束索引right,说明基准右边的元素都已经排好序,只需要对基准左边的元素进行排序,所以将leftkey - 1压入栈中。
    • 如果key既不等于left也不等于right,说明基准左右两边都有需要排序的元素,所以将leftkey-1key+1right的子数组分别压入栈中
  • 2.完成:当栈为空时,表示所有子数组都已排序完成,此时整个数组也已排序完成。

代码实现:

typedef int StackNode;
typedef struct Stack {StackNode* a;int real;int capacity;
}Stack;
void InitStack(Stack* p) {assert(p);p->a = NULL;p->capacity = p->real = 0;
}
//扩容
void expansion(Stack*p) {int newcapacity = p->capacity == 0 ? 4 : 2 * p->capacity;StackNode* tmp = (StackNode*)realloc(p->a, sizeof(StackNode) * newcapacity);if (tmp == NULL) {perror("expansion::realloc::NULL");exit(0);}p->a = tmp;p->capacity = newcapacity;
}
//入栈
void Push(Stack*p,int x) {assert(p);if (p->capacity == p->real) {expansion(p);}p->a[p->real++] = x;
}
//出栈
void Pop(Stack* p) {assert(p);p->real--;
}
void StackDestroy(Stack* p) {assert(p);free(p->a);p->a = NULL;p->capacity = p->real = 0;
}
//快排代码实现
void QuickSortNonR(int* a, int left, int right) {if (left >= right) {return;}Stack stack;InitStack(&stack);Push(&stack, left);Push(&stack, right);while (stack.real) {left = stack.a[stack.real - 2];right = stack.a[stack.real - 1];if (left == right) {Pop(&stack);Pop(&stack);continue;}int key = PartSort3(a, left, right);Pop(&stack);Pop(&stack);if (key == left) {Push(&stack, key + 1);Push(&stack, right);continue;}if (key == right) {Push(&stack, left);Push(&stack, key - 1);continue;}Push(&stack, key + 1);Push(&stack, right);Push(&stack, left);Push(&stack, key - 1);}StackDestroy(&stack);
}

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

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

相关文章

Jenkins安装 :AWS EC2 Linux

1 JDK11 install # 用的yum安装 # 压缩包安装&#xff0c;下载的jdk-11.0.22_linux-x64_bin.tar.gz在EC2解压&#xff0c;配置环境变量&#xff0c;运行jenkins的时候会报错$ yum -y list java-11* Available Packages java-11-amazon-corretto-devel.x86_64 …

动手学深度学习4.6 暂退法-笔记练习(PyTorch)

以下内容为结合李沐老师的课程和教材补充的学习笔记&#xff0c;以及对课后练习的一些思考&#xff0c;自留回顾&#xff0c;也供同学之人交流参考。 本节课程地址&#xff1a;丢弃法_哔哩哔哩_bilibili 本节教材地址&#xff1a;4.6. 暂退法&#xff08;Dropout&#xff09;…

LangChain技术解密:构建大模型应用的全景指南

&#x1f482; 个人网站:【 摸鱼游戏】【神级代码资源网站】【工具大全】&#x1f91f; 一站式轻松构建小程序、Web网站、移动应用&#xff1a;&#x1f449;注册地址&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交…

使用目标检测模型YOLO V9 OBB进行旋转目标的检测:训练自己的数据集(基于卫星和无人机的农业大棚数据集)

我看到YOLO V8中&#xff08;ultralytics版本8.2.18&#xff09;集成了YOLO V9&#xff0c;所以直接在YOLO V8 OBB的基础上实现YOLO V9 OBB&#xff0c;训练结果也出来了&#xff0c;但是评估指标比YOLO V8 OBB低一点点&#xff0c;不知道是不是哪里遗漏修改了......如有大神赐…

【Linux学习】进程间通信 (2) —— 信号

下面是有关进程通信中信号的相关介绍&#xff0c;希望对你有所帮助&#xff01; 小海编程心语录-CSDN博客 目录 1. 信号 1.1 概念 1.2 信号的产生 1.3 信号的处理方式 2. 函数 2.1 kill() 函数 2.2 signal()函数 2.3 sigaction()函数 2.4 sigprocmask()函数 …

文盘Rust -- 生命周期问题引发的 static hashmap 锁

100编程书屋_孔夫子旧书网 2021年上半年,撸了个rust cli开发的框架,基本上把交互模式,子命令提示这些cli该有的常用功能做进去了。项目地址:https://github.com/jiashiwen/interactcli-rs。 春节以前看到axum已经0.4.x了,于是想看看能不能用rust做个服务端的框架。 春节…

如何从Android恢复已删除的文件?3 种有效的方式

有时我们可能会错误地删除Android设备上的重要文件。更疯狂的是&#xff0c;Android手机上的文件在一夜之间消失了&#xff0c;我们不知道为什么。我们感到非常遗憾和恼火&#xff0c;但不知道。但是&#xff0c;此时学习如何从Android手机恢复已删除的文件为时已晚&#xff0c…

Excel 取出每组最后一行

Excel的前两列是两层的分组列&#xff0c;后两列是明细 ABCD1CM11112CM12123CM13134CM14145CM25156CM26167BM11218BM12229BM232310AM113111AM323212AM333313AM3434 现在要取出每小组的最后一行&#xff1a; ABCD1CM14142CM26163BM12224BM23235AM11316AM3434 使用 SPL XLL sp…

拼多多商品详情商品标题sku等信息抓取接口API调用步骤演示

接口名称&#xff1a;item_get_app_pro 公共参数 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,item_get,item_search_sho…

两台电脑怎么互传文件?这些方法你值得一试

在日常生活和工作中&#xff0c;我们经常需要在不同电脑之间传输文件&#xff0c;这可能是文档、照片、音乐或其他类型的文件。两台电脑怎么互传文件是非常有用的技能&#xff0c;可以提高工作效率并简化文件共享过程。本文将介绍三种常见的方法&#xff0c;帮助您了解如何在两…

苹果手机怎么看海拔高度?快速掌握使用技巧

手机不仅能满足我们日常的通讯需求&#xff0c;还内置了许多实用的功能&#xff0c;其中包括查看海拔高度。无论是登山、徒步、骑行还是只是好奇地想要了解所在地的海拔高度&#xff0c;苹果手机都能够满足您的需求。苹果手机怎么看海拔高度&#xff1f;在本文中&#xff0c;我…

wps能打开caj文件吗?CAJ应该如何打开?caj转pdf

问题1&#xff1a;wps能打开caj文件吗&#xff1f; WPS不能直接打开CAJ文件。 CAJ是中国知网开发的一种文件格式&#xff0c;主要用于存储学术文献&#xff0c;需要使用专门的阅读器才能打开。 问题2&#xff1a;CAJ应该如何打开&#xff1f; 要打开CAJ文件&#xff0c;你可…

羧甲基纤维素钠(CMC-Na)市场规模不断增长 我国生产企业众多

羧甲基纤维素钠&#xff08;CMC-Na&#xff09;市场规模不断增长 我国生产企业众多 羧甲基纤维素钠&#xff08;CMC-Na&#xff09;又称CMC-钠&#xff0c;化学式为[C6H7O2&#xff08;OH&#xff09;2OCH2COONa]n&#xff0c;是一种离子型纤维素醚。CMC-Na外观呈白色颗粒状或纤…

柳宗元,政治坎坷与文学辉煌的交织

&#x1f4a1; 如果想阅读最新的文章&#xff0c;或者有技术问题需要交流和沟通&#xff0c;可搜索并关注微信公众号“希望睿智”。 柳宗元&#xff0c;字子厚&#xff0c;生于唐代宗大历年间&#xff08;公元773年&#xff09;&#xff0c;卒于唐宪宗元和年间&#xff08;公元…

【全开源】在线题库微信小程序系统源码(ThinkPHP+FastAdmin+UniApp)

打造个性化学习平台 一、引言&#xff1a;在线学习的未来趋势 在数字化时代&#xff0c;线上学习已逐渐成为主流。随着移动互联网的普及&#xff0c;小程序以其轻便、快捷、无需安装的特点&#xff0c;成为用户日常学习的新选择。为了满足广大用户对于在线学习的需求&#xf…

光学测量反射率定标版

在光学测量和成像领域&#xff0c;准确性和一致性是至关重要的。为了确保设备能够提供可靠的数据&#xff0c;必须对其进行精确的校准。这就是反射率定标版发挥作用的地方。本文将深入探讨反射率定标版的概念、重要性、使用方式以及它们如何帮助科学家和工程师实现光学测量的精…

LeetCode刷题之HOT100之最长回文串

2024/5/28 大家上午好啊&#xff0c;我又来做题了 1、题目描述 2、逻辑分析 题目要求找出最长的回文子串。我回去看了一下回文数字和回文链表这两道题。这个题目的思想其实跟以上两题也差不多&#xff0c;但是结合了最长子串这一概念。那么怎么解决这个题目呢&#xff1f;那么…

Spark Sql写代码方式(yarn)以及 spark sql整合hive详解

引入部分&#xff1a;通常我们在IDEA中写spark代码中如果设置了loacl参数&#xff0c;基本都是在IDEA本地运行&#xff0c;不会提交到 standalone或yarn上运行&#xff0c;在前几篇文章中写的大多数都是该种形式的spark代码&#xff0c;但也写到了如何将spark代码提交到standal…

【VTKExamples::Utilities】第六期 DataAnimation

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 公众号:VTK忠粉 前言 本文分享VTK样例DataAnimation,并解析接口vtkProgrammableFilter,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U…

Windows远程桌面是什么?

Windows远程桌面是一种远程桌面协议&#xff0c;允许用户通过网络连接到远程Windows计算机&#xff0c;并在本地操作远程计算机。它为用户提供了访问远程计算机的便利性&#xff0c;可以在不同地区的电脑或设备之间进行信息远程通信。 天联解决方案 在远程桌面技术中&#xff…