排序进阶----快速排序

        当我们写了插入和希尔排序后,我们就应该搞更难的了吧。大家看名字就知道我们这篇博客的内容了吧。而且从名字上来看。快速排序就很快吧。那么为什么这个排序怎么能叫快速排序啊。我们希尔排序不是很快嘛。那么我们的快速排序肯定是有特殊之处嘞。不然这就太自负了。而且对于快速排序是用上了我们以前学的知识,二叉树。那我们为什么这么说嘞。我们下面就来讲讲嘛。

快速排序的思路

       其实对于看快速排序来说,我们理解的话还算是比较简单的。为什么这么说了,因为大家都已经大概了解了二叉数的用法了吧。我们这个快速排序设置一个值,但是这个值就是数组里面的,然后以他为主来左右行走。就是数组的头和尾,然后向中间寻找遇见比他大或者比他小的数,然后就进行交换,直到他们相遇。他们如果相遇了,那么可以表明的一件事就是他们相遇的地点一定会比我们设定的值大或者小。那么之所以会这样子呢,我们后面在实现的时候再谈论。所以总之上面我们说的就是把这个数组从左右两边开始移动后边的如果比我们设定值小,就先暂时停留,然后左边向中间移动,如果遇见比我们设定的值大的话就暂时停留,然后他们两个交换。接着继续往前走,如果他们两个相遇了的话,我们也能确定他们相遇的值是否比设定的值大或者小。后当他们相遇了之后,这就能用上我们二叉树的内容了。然后我们分左边和右边递归来实现这个。

快速排序的实现 

       当然实现快速排序的话,我们也还是像以前一样。先来写一个单趟。然后再实现整整体的过程。那么我们上面也说过了,需要先设定一个基准值。那我就先普遍设为头节点。当我们设置头节点后,我们还要向左右移动。那么我们这个还要再设置两个。那我当我们设置完这些之后,我们就可以开始向中间移动了。但是移动我们也有一个先后吧,到底是左先动还是右先动?如果我们以右先动的话,那么就是先找比我们设定值小的值就停下来然后就是左边移动。那么就会遇见比设定值小的值停下来。当达到这个目标之后我们就进行交换。知道他们两个相遇之后就结束。然后与这个值与我们的设定值进行交换。大家可能会想你怎么知道他们相遇的值会我设定的值小?这个大家需要先想一下。我们是让右边先走的。如果他们相遇,那肯定是右边走到了比他小的子才会停下来。然后左边才走。那么这是不是就确定了他们相遇的值比设定的值小。那么我们已经退出循环了,所以我们需要在手动的调整一下。这样,我们这单趟就结束了。

void xixi(int* a, int zuo, int you)
{//key确定基准值int key = zuo;int left = zuo;int right = you;while (left < right){//right先行动,找到比key小的值while (left < right && a[right] >= a[key]){right--;}//left行动,找到比key大的值while (left < right && a[left] <= a[key]){left++;}//到达指定位置,进行交换swap(&a[left], &a[right]);}//走完上面的步骤后,两个下标会相聚在一个位置//然后对这两个位置的值进行交换swap(&a[right], &a[key]);
}

        上面就是快速排序的单趟排序了,看起来是不是还是比较简单啊。就是比较确定下标然后交换数组的值。那么我们刚开始说过 快速排序是会用到二叉树的内容。我们既然单趟了那么下一趟怎么走呢?我不知道日常树就是递归值不一样而已。那么我们只需要将传进去的递归值改变从他们两个相遇的地方划分成为两部分,然后分为左部分和右部分。然后再分别理赔,周而复始,这样就排序好了。大家想想是不是这样的?所以在单趟排序的时候,我们还有一个事情需要处理一下,就是将key的值改变我们在最后的交换把key的改变写上,然后递归实现。

void QuickSort(int* a, int begin, int end)
{//结束条件if (begin >= end){return;}//一趟的实现int left = begin;int right = end;int keyi = left;while (left < right){//右边开始行动   一定要加上等于,因为快速排序找的是一定比它小的值while (left < right && a[keyi] <= a[right]){right--;}//左边开始行动while (left < right &&   a[left] <= a[keyi]){left++;}swap(&a[left], &a[right]);}swap(&(a[keyi]), &(a[right]));keyi = right;//[begin,keyi-1] keyi [keyi+1,end]QuickSort(a, begin, keyi - 1);//递归传递值QuickSort(a, keyi + 1, end);
}

         上面就是快速排序的基本方法了。当然都说只是基本方法了,那么他肯定还可以再进行优化。那他有哪些地方可以优化呢?我们接下来就来讲讲这些。

快速排序的优化 

1:      首先我们对于快速排序的优化就是我们最重要的key的值。我们快速排序,为什么key的值就始终是头节点了,我们不能换一个更加好一点儿的吗?所以我们的快速优化的第一个就是更改key的值。那么我们需要递归很多事,所以key的值需要更换很多次。那么我们就要写一个子函数来专门确定key的值。但是如何确定啊?这里就要用前辈的思想了。叫做三数取中。我们传递数组,和开头和结尾,然后我们计算开头和结尾中间的值比较,我们取中间的值,这样我们的快速排序就更加快速了。实现很简单:

//三数取中
int GetMid(int *a, int begin, int end)
{int mid = (begin + end) / 2;//平均的下标值if (a[begin] > a[end])//假设头大于尾的话{if (a[end] > a[mid])//尾大于平均那么尾就是中间的return end;else if (a[mid] > a[begin])//如过平均大于头的话头是中间值return begin;else//就只剩平均值了return mid;}else//(a[begin] < a[end])假设头大小于尾的话{if (a[end] < a[mid])//平均大于尾。则为是中间return end;else if (a[begin] < a[mid])//平均大于头的话,平均就是中间return mid;else//就只剩头了return begin;}
}

2:          另外一个优化方法就简单粗暴了许多了。因为我们都说快速排序嘛,要比我们前面学了几个排序都要好一些,而且我们也知道我们前面写的几个排序中插入排序对。小数组计算更快。我们就判断如果数组大于十的话,我们就快拍,如果小于十的话,我们就用插入排序。这就是大的用大的方法,小的用小的方法,这样我们是不是要方便许多? 但是我们要注意1.插入排序之后两个参数,一个是数据集合的起点地址,第二个是数据量。2.使用插入排序时,我们要传入待排序数据集合的其实地址,即a+begin,如果传入的是a,那排序的永远都是数组a的前n个区间。3.插入排序传入的是数据个数,所以我们要将end-begin加上1之后才传入。快速排序中end、begin都是闭区间(即数组下标)。如果大家对于插入排序还是不了解的话,可以看一下我上一篇博客。

void QuickSort_Pointer(int* a, int begin, int end)
{if (begin >= end){return;}//数据区间大与10,进行快速排序if (end - begin > 10){int prev = begin;int cur = begin + 1;int keyi = begin;//三数取中后对keyi位置的值进行交换int mid = GetMid(a, begin, end);swap(&a[mid], &a[keyi]);while (cur <= end){if (a[cur] < a[keyi] && ((++prev) != cur)){swap(&a[cur], &a[prev]);}cur++;}swap(&a[prev], &a[keyi]);keyi = prev;//开始进行递归QuickSort_Pointer(a, begin, keyi - 1);QuickSort_Pointer(a, keyi + 1, end);}else{//左闭右闭InsertSort(a, end - begin + 1);InsertSort(a + begin, end - begin + 1);}}
总结

      那么说明的就是我们快速拍摄的大概所有内容了。当然还有一种优化其实也是可以的,叫做挖坑法。这个如果大家感兴趣的话可以自己去了解一下。当然我的内容是不是很完全的。所以大家可以在评论区里面也说一下,自己感兴趣的话,我下一篇博客会补充的。

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

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

相关文章

autodl服务器中YOLOx训练自己数据集

目录 本篇文章主要讲解使用YOLOx训练自己数据集&#xff0c;其中包括数据集格式转换~ 目录 一、数据集处理二、环境配置三、配置文件修改四、开始训练五、开始验证 一、数据集处理 第一步&#xff1a;将yolo格式的数据集转换成VOC格式 转换脚本&#xff1a;txt_to_xml.py f…

[力扣题解] 222. 完全二叉树的节点个数

题目&#xff1a;222. 完全二叉树的节点个数 思路 随便一种遍历方式都行 代码 Method 1 : Me class Solution { public:int countNodes(TreeNode* root) {if(root NULL){return 0;}int result 0;queue<TreeNode*> que;que.push(root);while(!que.empty()){ resu…

Unity DOTS技术(二)ECS

文章目录 一.ECS简介二.基本操作实例三.实体查看组件四.位置实体修改五.旋转实体六.了解原有属性七.禁止自动创建八.动态实例化 一.ECS简介 ECS全称 (Entity Component System).即(E:实体 C:组件 S:系统). 实际上即是数据方法分离.数据放在组件里,具体实现放在系统里.组件挂载…

Debian系统磁盘挂载

服务器推荐&#xff1a;雨云 优惠码&#xff1a;zsj 用优惠码注册账户并绑定微信后可获取首月5折优惠券&#xff1b; 后续新购主机也可在积分商城中换取新购优惠券&#xff1b; 公测阶段的超大带宽服务器&#xff0c;由于是国内主机因此需要备案域名。 公测阶段价格尚未确定&am…

google的chromedriver最新版下载地址

Chrome for Testing availability (googlechromelabs.github.io) 复制对应的地址跳转进去即可下载&#xff0c;下载前先看下自己google浏览器版本&#xff0c;找到对应的版本号去下载&#xff0c;把解压缩的exe放到google浏览器目录下。

使用python统计word文档页数

使用python统计word文档页数 介绍效果代码 介绍 使用python统计word文档的页数 效果 代码 import os import comtypes.clientdef get_word_page_count(docx_path):try:# Initialize the COM objectword comtypes.client.CreateObject(Word.Application)word.Visible False…

嵌入式人工智能开发:基于TensorFlow Lite和Edge TPU的实时对象检测系统

文章目录 引言环境准备人工智能在嵌入式系统中的应用场景代码示例常见问题及解决方案结论 1. 引言 随着人工智能&#xff08;AI&#xff09;和物联网&#xff08;IoT&#xff09;技术的快速发展&#xff0c;嵌入式系统中集成AI技术已成为一种趋势。实时对象检测是AI在嵌入式…

【JavaScript】JS语法基础

逗号运算符 逗号运算符可以用于分隔多个子表达式&#xff0c;从左到右执行每个表达式&#xff0c;并返回最后一个子表达式的值作为整个表达式的结果 let x 1; x (x, x); console.log(x); // Expected output: 2x (2, 3); console.log(x); // Expected output: 3Function 对…

Outpainting Inpainting

文章目录 what is Inpainting&#xff08;补画&#xff09;?what is Outpainting&#xff08;扩画&#xff09;?The way to realize Outpainting summaryOthers what is Inpainting&#xff08;补画&#xff09;? 称为图像修复或图像填充&#xff0c;是一种技术&#xff0c;…

Nature Communications|柔性自驱动仿生眼(离子凝胶/仿生眼/柔性电子)

2024年4月10日,黄维(Wei Huang)院士、南京工业大学刘举庆(Juqing Liu)教授和刘正东(Zhengdong Liu)副教授课题组,在《Nature Communications》上发布了一篇题为“A bionic self-driven retinomorphic eye with ionogel photosynaptic retina”的论文,罗旭(Xu Luo)、陈晨(…

基于springboot的宠物领养系统源码数据库

基于springboot的宠物领养系统源码数据库 如今社会上各行各业&#xff0c;都在用属于自己专用的软件来进行工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。互联网的发展&#xff0c;离不开一些新的技术&#xff0c;而新技术的产生往往是为了解决…

ESP-01S 使用 arduino 烧录程序

一、设置 arduino 编辑器 1、文件-首选项-附加开发版管理网址中添加 http://arduino.esp8266.com/stable/package_esp8266com_index.json 2、工具-开发板管理 搜索 8266 并下载 ) 3、工具-开发板 在 8266 里面选择 Generic ESP8266 Module 4、工具-端口 记得选择对应的端口 …

问题排查|记录一次基于mymuduo库开发的服务器错误排查(回响服务器无法正常工作)

问题背景&#xff1a; 服务器程序如下&#xff1a; #include <mymuduo/TcpServer.h> #include <mymuduo/Logger.h>#include <string> #include <functional>class EchoServer { public:EchoServer(EventLoop *loop,const InetAddress &addr, con…

【LeetCode 1】两数之和

1. 题目 两数之和 2. 分析 这道题有多种解法&#xff0c;逐个来看。 2.1 深搜版 首先可以用深搜来解&#xff0c;我们从数组集合中选取两个数&#xff0c;判断其和是不是target&#xff0c;如果是则满足要求&#xff0c;如果不是&#xff0c;继续选取。 2.2 循环版 深搜…

【简单讲解下Fine-tuning BERT,什么是Fine-tuning BERT?】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

STM32作业实现(五)温湿度传感器dht11

目录 STM32作业设计 STM32作业实现(一)串口通信 STM32作业实现(二)串口控制led STM32作业实现(三)串口控制有源蜂鸣器 STM32作业实现(四)光敏传感器 STM32作业实现(五)温湿度传感器dht11 STM32作业实现(六)闪存保存数据 STM32作业实现(七)OLED显示数据 STM32作业实现(八)触摸按…

数据库(16)——DQL执行顺序

DQL的执行顺序 这是DQL的编写顺序。 而实际的执行顺序为

【LeetCode:575. 分糖果+ 哈希表】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

职场思考-在行业坚守中实现个人增值(13)

滚石不生苔&#xff0c;转行不聚财 在自己工作几年后&#xff0c;职业竞争力会由专业能力向行业经验进行转化 如果你不具备足够的行业积累&#xff0c;即使在某个专业上有足够的能力&#xff0c;你也难以得到待遇或职位的提升&#xff0c;陷入高不成低不就的局面 掌握完成岗位工…

Java基础——四、关键字

四、关键字 Java关键字是Java编程语言中保留的词汇&#xff0c;这些词汇具有特殊的意义和用途&#xff0c;用于定义数据类型、控制程序的流程、声明类和方法等。Java关键字不能作为变量名、方法名、类名或任何其他标识符使用。下面是一些常见的Java关键字及其简要说明&#xf…