【数据结构】快速排序(4种方式实现)

前言:前面我们学习了几种相对比较简单的排序,今天我们要一起学习的是快速排序,我们将通过四种方式来模拟实现快排。

💖 博主CSDN主页:卫卫卫的个人主页 💞
👉 专栏分类:数据结构 👈
💯代码仓库:卫卫周大胖的学习日记💫
💪关注博主和博主一起学习!一起努力!
在这里插入图片描述


C语言算法-快速排序

什么是快速排序

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

快速排序之hoare版

hoare思想

1.首先我们选定一个基准值,通常是数组中的第一个元素。
2. 定义俩个指针,一个left一个right分别在数组的最左边和最右边。
3. 我们让右指针先走,如果比我们定义的基准值小就停下来。
4. 右指针走完我们在让左指针走,如果比我们定义的基准值小也停下来。
5. 在俩个指针都停下来的时候把它们的值进行交换,以此反复循环直到俩个指针相遇,我们把基准值和它们的值进行交换。
6. 最终这一趟下来我们会得到如下图一样的数据,基准值左边的都比基准值小,右边的都比基准值大。
7. 我们把这一趟走完后在重新分为左右俩个部分的数据,在用此方法以此往复即可实现一个有序数组。

请添加图片描述
代码思路:刚刚我们用那个思想可以实现一次的排序过程,可是排完一次那剩下的怎么排呢?我们可以把这个问题拆成许多个小问题(如下图所示),因此我们可以采用递归的思想来实现它。
在这里插入图片描述


代码实现:

void QuickSort1(int* a,int begin, int end)//快速排序 -- hoare
{int right = end;int left = begin;int key = begin;if (begin >= end){return;}while (left < right){while (a[right] >= a[key] && right >left){right--;}while (a[left] <= a[key] &&  right > left){left++;}Swap(&a[right], &a[left]);}Swap(&a[key], &a[left]);key = left;QuickSort1(a, begin, left - 1);//左边QuickSort1(a, key+1, end);//右边
}

测试函数:

void Test_QuickSort1()
{int a[] = { 20,16,30,18,12,21,26,21 };QuickSort1(a, 0, sizeof(a) / sizeof(a[0]) - 1);PrintArray(a, sizeof(a) / sizeof(a[0]));}

运行结果:
在这里插入图片描述


快速排序之挖坑法

挖坑思想:

  1. 首先我们和前面的hoare法一样,我们选定一个基准值,通常是数组中的第一个元素。
  2. 我们定义一个坑位(hole)放在基准值的位置的下面。
  3. 我们同理定义俩个指针leftright一个在数组的最左边一个在最右边。
  4. 不同的是,我们right指针找到比基准值小的值的时候,就直接和坑位所对应的值交换,并把right此时的位置置为hole
  5. 同理left也行动开始找值补坑,找到比基准值大的值将其放入坑位,置为新的坑。
  6. 以此往复,当leftright相遇的时候,在将基准值放入坑位。此时我们也会发现和hoare一样的排序结果,右边的值都比基准小,左边的都比其大。(如下图所示)
    请添加图片描述

代码实现:

void PartSort2(int* a,int begin ,int end)//快速排序 -- 挖坑法
{int right = end;int left = begin;int hole = left;int key = a[begin];if (begin >= end){return;}while(left < right){while(a[right] >= key && right > left){right--;}a[hole] = a[right];hole = right;while (a[left] <= key && right > left){left++;}a[hole] = a[left];hole = left;}a[hole] = key;QuickSort1(a, begin, hole - 1);//左边QuickSort1(a, hole + 1, end);//右边
}

测试函数:

void Test_PartSort2()
{int a[] = { 20,16,30,18,12,21,26,21 };PartSort2(a, 0, sizeof(a) / sizeof(a[0]) - 1);PrintArray(a, sizeof(a) / sizeof(a[0]));}

运行结果:
在这里插入图片描述


快速排序之前后指针法

双指针思想

双指针法相较于前面俩种方式,是目前主流的一种写法,这里我们依然来看看单趟的走法。

  1. 这里我们依然和前面的俩种法一样,我们选定一个基准值,通常是数组中的第一个元素。
  2. 定义一个pre和一个cur指针,同理,我们让cur指针先走,如果遇到比基准值小的值我们就停下来,然后让pre指针往前走一步,我们再对其进行交换。
  3. 注意,在交换的时候我们pre指针和cur指针不能是处于同一位置。
  4. pre指针和cur指针相遇的时候,我们就让此次循环终止,在将基准值和此时的pre值进行交换即可(cur值可能已经走出边界所以不能是cur)。此时我们也会发现和hoare和挖坑法一样的排序结果,右边的值都比基准小,左边的都比其大。(如下图所示)
    请添加图片描述

代码实现

void PartSort3(int* a, int begin, int end)//双指针法   //cur遇到比key大的++cur    cur遇到比key小的值,++prev,交换pre和cur的位置的值, ++cur
{int pre = begin;int cur = pre+1;int key = begin;while (cur <= end && pre <= end){if(a[cur] < a[key] && cur != ++pre){Swap(&a[cur], &a[pre]);}++cur;}Swap(&a[key], &a[pre]);QuickSort1(a, begin, pre - 1);//左边QuickSort1(a, pre + 1, end);//右边
}

函数测试

void Test_PartSort3()
{int a[] = { 20,16,30,18,12,21,26,21 };PartSort3(a, 0, sizeof(a) / sizeof(a[0]) - 1);PrintArray(a, sizeof(a) / sizeof(a[0]));
}

运行结果:
在这里插入图片描述


快速排序之非递归排序

非递归思想

因为递归是在函数栈帧是在栈上开辟的,十分容易出现溢出的现象,为了防止这个问题,我们有一种非栈帧的方式来实现排序,就是通过非递归的方式来实现,即用栈(前面所学的数据结构中的栈)来模拟实现。

  1. 入栈一定得保证先左再右即我们先进去的是左区间,再进去的是右区间。
  2. 将每次入栈的数据进行单趟排序。
  3. 再将剩余的部分划分成 [left,key-1][key+1,right]
  4. 循环此操作直到栈中的数据全部为空即可(如果不理解可以看下图)。
    在这里插入图片描述

代码实现:

int PartSort4(int* a, int begin, int end)//双指针法   //cur遇到比key大的++cur    cur遇到比key小的值,++prev,交换pre和cur的位置的值, ++cur
{int pre = begin;int cur = pre + 1;int key = begin;while (cur <= end && pre <= end){if (a[cur] < a[key] && cur != ++pre){Swap(&a[cur], &a[pre]);}++cur;}Swap(&a[key], &a[pre]);key = pre;return key;
}void QuickSortNonR(int* a, int left, int right)
{ST st;STInit(&st);STPush(&st, left);STPush(&st, right);while (!STEmpty(&st)){int end = STTop(&st);//右边STPop(&st);int begin = STTop(&st);//左边STPop(&st);int key = PartSort4(a, begin,end);//第一趟排序的区间//[left, key - 1] key [key + 1, right];if (key + 1 < end)//判断此时是左区间还是右区间{STPush(&st, key + 1);STPush(&st, end);}if (begin < key - 1){STPush(&st, begin);STPush(&st, key - 1);}}STDestroy(&st);
}

测试函数:

void Test_QuickSortNonR()
{int a[] = { 20,16,30,18,12,21,26,21 };QuickSortNonR(a,0, sizeof(a) / sizeof(a[0]) - 1);PrintArray(a, sizeof(a) / sizeof(a[0]));}

运行结果:
在这里插入图片描述


结语:今天的内容就到这里吧,谢谢各位的观看,如果有讲的不好的地方也请各位多多指出,作者每一条评论都会读的,谢谢各位。


🫵🫵🫵 这里提前祝各位新年快乐呀! 💞

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

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

相关文章

K-means 聚类算法分析

算法简述 K-means 算法原理 我们假定给定数据样本 X &#xff0c;包含了 n 个对象 &#xff0c;其中每一个对象都具有 m 个维度的属性。而 K-means 算法的目标就是将 n 个对象依据对象间的相似性聚集到指定的 k 个类簇中&#xff0c;每个对象属于且仅属于一个其到类簇中心距离…

基于MINIST的手写数字体识别

一、算法简述 网络结构设计 通过创建MnistNet类&#xff0c;定义了包含两个卷积层和两个全连接层的深度神经网络。这个网络的设计灵感来自于经典的CNN结构&#xff0c;其中卷积层用于提取图像特征&#xff0c;而全连接层则用于将这些特征映射到最终的类别。 卷积与池化 卷…

js对象方法大全(开发必会)

目录 前言 assgin(对象合并) 参数 功能 返回值 测试 结果 结论 create(以源对象为原型创建新对象) 参数 功能 返回值 测试 结果 结论 defineProperties(对属性进行具体定义) 参数 功能 返回值 测试 结果 结论 defineProperty(重写或定义新属性) 参数 功…

【Hive_04】分区分桶表以及文件格式

1、分区表1.1 分区表基本语法&#xff08;1&#xff09;创建分区表&#xff08;2&#xff09;分区表读写数据&#xff08;3&#xff09;分区表基本操作 1.2 二级分区1.3 动态分区 2、分桶表2.1 分桶表的基本语法2.2 分桶排序表 3、文件格式与压缩3.1 Hadoop压缩概述3.2 Hive文件…

用轻量级ORM--Dapper实现泛型仓储

阅读本文你的收获 了解Dapper的适用场景了解Dapper的本质其实是一些扩展方法学会使用Dapper的扩展Domel来实现泛型仓储 一、什么是Dapper&#xff1f; Dapper是一个轻量级的ORM&#xff08;对象关系映射&#xff09;工具&#xff0c;用于简化数据库操作。它和Entity Framewor…

Java 类加载与字节码技术

3 类加载与字节码技术 3.1 类文件结构 类文件结构字节码指令编译期处理类加载阶段类加载器运行期优化 根据 JVM 规范&#xff0c;类文件结构如下 ClassFile {u4 magic;u2 minor_version; // 小版本号u2 major_version; // 主版本号u2 constant_pool_count; // 常量池cp_info…

web前端开发网页制作html/css结课作业

效果图展示&#xff1a; 注意事项&#xff1a; 引用JQuery文件地址和图片地址要更换一下。 百度网盘链接&#xff1a; http://链接&#xff1a;https://pan.baidu.com/s/1wYkmLr7csjBwQY6GmlYm4Q?pwd4332 提取码&#xff1a;4332 html界面展示&#xff1a; main.css代码部…

前端 -- 基础 常用标签 ( 文本格式化标签,<div>,<span>标签)

目录 文本格式化标签 &#xff1a; 加粗 倾斜 删除线 下划线 < div > 和 < span > 标签 < div > 标签 < span > 标签 文本格式化标签 &#xff1a; 在网页中&#xff0c;有时需要为文字设置 粗体&#xff0c; 斜体 或下划线 等效果&a…

儿童学python语言能做什么,孩子学python哪个机构好

大家好&#xff0c;小编为大家解答儿童学python语言能做什么的问题。很多人还不知道孩子学python哪个机构好&#xff0c;现在让我们一起来看看吧&#xff01; Source code download: 本文相关源码 我们准备了很久的Python3课程终于要来了。 为什么Python3课程花了我们这么久的时…

一篇文章带你入门PHP魔术方法

PHP魔术方法 PHP 中的"魔术方法"是一组特殊的方法&#xff0c;它们在特定情况下自动被调用。这些方法的名称都是以两个下划线&#xff08;__&#xff09;开头。魔术方法提供了一种方式来执行各种高级编程技巧&#xff0c;使得对象的行为可以更加灵活和强大。以下是一…

机器学习模型可解释性的结果分析

模型的可解释性是机器学习领域的一个重要分支&#xff0c;随着 AI 应用范围的不断扩大&#xff0c;人们越来越不满足于模型的黑盒特性&#xff0c;与此同时&#xff0c;金融、自动驾驶等领域的法律法规也对模型的可解释性提出了更高的要求&#xff0c;在可解释 AI 一文中我们已…

OpenHarmony南向之Camera简述

Camera驱动框架 该驱动框架模型内部分为三层&#xff0c;依次为HDI实现层、框架层和设备适配层&#xff1a; HDI实现层&#xff1a;实现OHOS&#xff08;OpenHarmony Operation System&#xff09;相机标准南向接口。框架层&#xff1a;对接HDI实现层的控制、流的转发&#x…