【排序】——2.快速排序法(含优化)
快速排序法
递归法
霍尔版本(左右指针法)
1.思路
1、选出一个key,一般是最左边或是最右边的。
2、定义一个begin和一个end,begin从左向右走,end从右向左走。(需要注意的是:若选择最左边的数据作为key,则需要end先走;若选择最右边的数据作为key,则需要bengin先走)。
3、在走的过程中,若end遇到小于key的数,则停下,begin开始走,直到begin遇到一个大于key的数时,将begin和right的内容交换,end再次开始走,如此进行下去,直到begin和end最终相遇,此时将相遇点的内容与key交换即可。(选取最左边的值作为key)
4.此时key的左边都是小于key的数,key的右边都是大于key的数
5.将key的左序列和右序列再次进行这种单趟排序,如此反复操作下去,直到左右序列只有一个数据,或是左右序列不存在时,便停止操作,此时此部分已有序
📝tip1
- 常选左为key,那右边先走。
📝优化一:选key的常见三种方法
-
1.三数取中(比较推荐)
- 三数取中 left mid right
- 大小居中的值,也就是不是最大也不是最小的
-
2.随机取一个
-
3.取中间位置
//关于选kevi——三数取中,作为kevi(比较好)
int Getmid(int* arr, int left, int right)
{//方法1:三数取中//left mid right//找到三者——中间值的下标,返回int mid = (left + right) / 2;if (arr[left] < arr[mid]){if (arr[mid] < arr[right]){return mid;}else if(arr[right]<arr[mid]){return right;}else{return left;}}else //此时已经arr[left]>arr[mid]{if (arr[right] < arr[mid]){return mid;}else if (arr[left] < arr[right]){return left;}else{return right;}}
}
//方法2:随机取一个(还行)
int GetRand(int* arr, int left, int right)
{srand((size_t)time(NULL));return rand() % (right-left+1)+left;
}
//方法3:取中间位置
int GetMid(int* arr, int left, int right)
{return (left + right) / 2;
}
📝优化二:小区间优化
优化小数组的交换,就是为了解决大才小用问题
原因:对于很小和部分有序的数组,快排不如插排好。当待排序序列的长度分割到一定大小后,继续分割的效率比插入排序要差,此时可以使用插排而不是快排
截止范围:待排序序列长度N = 10,虽然在5~20之间任一截止范围都有可能产生类似的结果,这种做法也避免了一些有害的退化情形。
if (right - left + 1 < 10)
{InsertSort(a + left, right - left + 1); //使用插入排序return;
}
2.图解
单趟动图:
3.代码
代码如下:
//hoare(霍尔)版本(左右指针法)
#include<stdio.h>
void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
void QuickSort(int* arr,int left,int right)
{//递归终止条件if (left >= right)return;//记录一下,因为后面要变化int begin=left;int end=right;//选左边为keyint mid = Getmid(arr, left, right); //三数取中Swap(&arr[mid],&arr[left]); //把找到的,移到最左边int kevi = left;while (left < right){//右先走// 注意:left<right//right,找小while (left < right &&arr[right] >= arr[kevi]){right--;}//left找大while (left < right && arr[left]<= arr[kevi]){left++;}//交换(大和小的)Swap(&arr[left], &arr[right]);}//交换key和相遇点Swap(&arr[kevi], &arr[right]);kevi = right; //更新kevi//递归// 右边大于kevi 左边小于kevi//此时[begin,kevi) kevi [kevi+1,end]QuickSort(arr, begin,kevi-1);QuickSort(arr, kevi+1,end);
}
运行结果:
挖坑法
1.思路
- 选key,左边为key(坑)
- 右边先走,找小(小于key),找到把值放key(坑里),此时right变新坑
- 左边后走,找大(大于key),找到把值放key(坑里),此时left变新坑。
- 一直相遇,把一开始key的值放相遇点
- 递归下去
2.图解
3.代码
//挖坑法
void QuickSort_keng(int* arr,int begin,int end)
{//递归结束if (begin >= end)return;//int left = begin;int right = end;int mid = Getmid(arr, left, right); //三数取中Swap(&arr[mid], &arr[left]); //换过来int kevi = arr[left]; //设置开始的坑位,保存key的值int keng = left; //记录坑位的位置while (left < right){//right 找小while (left<right&&arr[right] >= kevi){right--;}Swap(&arr[right], &arr[keng]); //交换,right位置变成新的坑位keng = right;//left找大while (left < right && arr[left] <= kevi){left++;}Swap(&arr[left], &arr[keng]); //交换,left位置变成新的坑位keng = left; }//最终把kevi放keng位置(相遇点)arr[keng] = kevi;//递归QuickSort_keng(arr,begin,keng-1);QuickSort_keng(arr, keng+1, end);}
前后指针法
1.思路
- 1、选出一个key,一般是最左边或是最右边的。
- 2、起始时,prev指针指向序列开头,cur指针指向prev+1(前后指针)。
- 3、若cur指向的内容小于key,则prev先向后移动一位,然后交换prev和cur指针指向的内容,然后cur指针++;
- 4、若cur指向的内容大于key,则cur指针直接++。如此进行下去,直到cur到达end位置,此时将key和++prev指针指向的内容交换即可。
经过一次单趟排序,最终也能使得key左边的数据全部都小于key,key右边的数据全部都大于key。
然后也还是将key的左序列和右序列再次进行这种单趟排序,如此反复操作下去,直到左右序列只有一个数据,或是左右序列不存在时,便停止操作
2.图解
3.代码
void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
//前后指针版本
void QuickSort_prev(int* arr, int begin, int end)
{//递归结束if (begin >= end) return;记录区间范围int left =begin;int right = end;int kevi = left; //记录key的下标//前后指针int prev =left;int cur = left + 1;while (cur <= right){if (arr[cur] < arr[kevi] && ++prev != cur){//把小的交换到前面Swap(&arr[cur],&arr[prev]);}cur++;}//cur越界了,交换kevi和prevSwap(&arr[kevi], &arr[prev]);kevi = prev;//递归QuickSort_prev(arr, left, kevi - 1);QuickSort_prev(arr, kevi + 1, right);}
非递归法
1.思路
-
使用stack来存储待处理的区间,先入栈的是右端点,然后是左端点。
-
在while循环中,只要栈不为空,就继续处理。
-
每次从栈中弹出两个元素,分别代表当前处理区间的左右端点。
-
执行一趟快速排序的划分操作,使用kevi作为基准元素的索引,prev用于记录小于基准元素的最后一个元素的位置。
-
在while循环中,cur遍历当前区间,如果发现比基准元素小的元素,则将其与prev位置的元素交换。
-
划分完成后,将基准元素与prev位置的元素交换,确保基准元素位于中间位置。
-
检查新的区间是否需要继续排序,如果需要,则将新的区间端点压入栈中。
-
重复步骤2-7,直到栈为空,这意味着所有元素都已经被排序。
2.图解
3.代码
这里得单趟,我套用了前面 前后指针的方法
//非递归
void QuickSort_None(int* arr, int begin, int end)
{stack<int> st; //栈//先入右,后入左st.push(end);st.push(begin);//不为空while (!st.empty()){//出栈区间,开始一趟int left = st.top();st.pop();int right = st.top();st.pop();//走单趟int kevi = left;int prev = left;int cur = left+1;while (cur <= right){//把小的换到前面if (arr[cur] < arr[kevi] && ++prev != cur){Swap(&arr[prev], &arr[cur]);}++cur;}//把kevi换到相遇点Swap(&arr[kevi],&arr[prev]);kevi = prev;//入栈新区间-先右后左// [begin,kevi-1] kevi [kevi+1,end]if (kevi + 1 < right){st.push(end); //先右后左st.push(kevi+1);}if (left<kevi-1){st.push(kevi-1); // 先右后左st.push(left);}}
}
算法性能
1.时间复杂度
2.空间复杂度
3.稳定性
不稳定
下面2 2 1 的例子,两个2相对位置发生变化
相关文章:

【排序】——2.快速排序法(含优化)
快速排序法 递归法 霍尔版本(左右指针法) 1.思路 1、选出一个key,一般是最左边或是最右边的。 2、定义一个begin和一个end,begin从左向右走,end从右向左走。(需要注意的是:若选择最左边的数据作为key,则…...

AnaTraf | 网络分析系统:高效IT运维工具
目录 什么是网络分析系统? 网络分析系统的核心功能 二、网络分析系统在IT运维中的重要性 案例分析:如何快速应对网络拥塞 技巧分享:如何使用网络分析系统优化带宽 网络分析系统的部署与最佳实践 确定监控范围与关键设备 分析结果的可…...

踩坑日记:线上接口超时问题排查
1.背景: 上线后,功能测试. 进入小程序页面发现很慢,耗时超过5秒,打开skywalking发现大量接口耗时都很高. 2.top命令 服务器top命令查看cpu资源发现占用并不高 3.mysql查看sql运行情况 # 当前运行的所有事务 select * from information_schema.innodb_trx; 1 | …...

C语言中的段错误(Segmentation Fault):底层原理及解决方法
引言 在C语言编程中,“段错误”(通常由操作系统信号 SIGSEGV 触发)是一种常见的异常情况,它表明程序试图访问不受保护的内存区域。本文将深入探讨段错误的原因、底层原理、常见情况以及如何调试和解决这类错误。 段错误的定义 …...
1.两数之和 暴力枚举和暴力搜索法
1. 两数之和 已解答 简单 相关标签 相关企业 提示 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案,并且你不能使用两次相…...

你的收入达到了缴纳个人所得税的标准了吗?
在现代社会,个人所得税作为一种重要的税收形式,已经渗透到了我们每个人的日常生活中。它不仅关乎国家的财政收入,更与每个纳税人的切身利益息息相关。那么,你是否真正了解个人所得税的缴纳标准、计算方法以及相关的税收优惠政策呢…...

【C++贪心】2086. 喂食仓鼠的最小食物桶数|1622
本文涉及知识点 C贪心 LeetCode2086. 喂食仓鼠的最小食物桶数 给你一个下标从 0 开始的字符串 hamsters ,其中 hamsters[i] 要么是: ‘H’ 表示有一个仓鼠在下标 i ,或者’.’ 表示下标 i 是空的。 你将要在空的位置上添加一定数量的食物桶…...

notepad++中实现代码整体缩进和退格
我 | 在这里 ⭐ 全栈开发攻城狮、全网10W粉丝、2022博客之星后端领域Top1、专家博主。 🎓擅长 指导毕设 | 论文指导 | 系统开发 | 毕业答辩 | 系统讲解等。已指导60位同学顺利毕业 ✈️个人公众号:乡下小哥编程。回复 Java全套视频教程 或 前端全套视频教…...

如何调整配置请款单上的立账条件
顾问配置的立账条件取的是供应商档案里面的参数。与实际需求是不相匹配的。采购员商谈的立账条件经常是变化的。 措施:修改模板中立几账条件的OQL语句。 如下: select UFIDA::U9::AP::APBill::APBillHead.APBillLines.AccrueTerm.Name as 立账条件_名…...

骨传导耳机精选:2024最佳骨传导耳机有哪些?分享骨传导耳机top5
随着健康意识的普及,越来越多的人开始注重运动健身,并将音乐作为运动时的重要伴侣。然而,传统耳机在运动时易脱落且不易清洁的问题,给健身爱好者们带来了不少困扰。幸运的是,骨传导耳机的出现为这一问题提供了解决方案…...
for循环与webAPI练习题
爱太容易了,让爱维持才是最困难的部分 文章目录 for循环练习题webAPI练习题 for循环练习题 练习1:计算1-100的和 let sum 0for (let i 1; i < 100; i) {sum i}console.log(sum)练习2:将1-100之间所有是6的倍数的数字输出到控制台 for …...

FLUX | 轻松掌握FLUX.1 LoRA本地训练秘籍!
在数字艺术和创意领域,FLUX以其独特的虚实结合技术,已经成为艺术家和设计师们手中的利器。今天,我们激动地宣布,FLUX推出了一款全新的FLUX.1版本,它将LoRA本地训练技术完美融合,为用户提供了更加便捷和高效…...
LeetCode 每日一题 最小元素和最大元素的最小平均值
最小元素和最大元素的最小平均值 你有一个初始为空的浮点数数组 averages。另给你一个包含 n 个整数的数组 nums,其中 n 为偶数。 你需要重复以下步骤 n / 2 次: 从 nums 中移除 最小 的元素 minElement 和 最大 的元素 maxElement。 将 (minElement ma…...

PHP学习记录-编辑器推荐和本地环境的安装
文章目录 一,编辑器首推VSCode1,vscode2,PHPStorm 二,PHP环境搭建1,下载安装2,使用phpstudy创建站点3,答疑解惑 一,编辑器首推VSCode 1,vscode 对于PHP新手来说&#x…...

嵌套div导致子区域margin失效问题解决
嵌套div导致子区域margin失效问题解决 现象原因解决方法 现象 <div class"prev"></div> <div class"parent"><div class"child"></div><div class"child"></div> </div> <div cl…...
搭建app业务的服务器优势类型用途等
APP服务器的服务类型有哪些 APP服务器主要包括API服务器、数据库服务器、Web服务器等。API服务器可以提供登录、注册、查询、更新等各种API服务,为APP提供更方便的功能;数据库服务器可以存储APP数据,访问更快、更安全;Web服务器可…...

基于Springboot+Vue的个性化推荐影院(含源码数据库)
1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 这个系…...

SpringMVC后台控制端校验-表单验证深度分析与实战优化
前言 在实战开发中,数据校验也是十分重要的环节之一,数据校验大体分为三部分: 前端校验后端校验数据库校验 本文讲解如何在后端控制端进行表单校验的工作 案例实现 在进行项目开发的时候,前端(jquery-validate),后端,数据库都要进行相关的数据…...

Codeforces Round 770 (Div. 2)
比赛链接:Dashboard - Codeforces Round 770 (Div. 2) - Codeforces A. Reverse and Concatenate 题意: 思路: 假设 s "abba" 经过1次操作后 -> "abbaabba" s "abcd" 经过一次操作后 -> "abcd…...
ProteinMPNN中蛋白质特征提取
函数 featurize 的主要作用是将一批蛋白质序列和结构信息转化为深度学习模型可以接受的特征矩阵。它在处理蛋白质多链结构(即多个链的蛋白质复合体)时,考虑了可见链和被掩码链的区分。 代码: import torch import numpy as np import csv import time import os import r…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...

Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...

热烈祝贺埃文科技正式加入可信数据空间发展联盟
2025年4月29日,在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上,可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞,强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...
Linux安全加固:从攻防视角构建系统免疫
Linux安全加固:从攻防视角构建系统免疫 构建坚不可摧的数字堡垒 引言:攻防对抗的新纪元 在日益复杂的网络威胁环境中,Linux系统安全已从被动防御转向主动免疫。2023年全球网络安全报告显示,高级持续性威胁(APT)攻击同比增长65%,平均入侵停留时间缩短至48小时。本章将从…...
多元隐函数 偏导公式
我们来推导隐函数 z z ( x , y ) z z(x, y) zz(x,y) 的偏导公式,给定一个隐函数关系: F ( x , y , z ( x , y ) ) 0 F(x, y, z(x, y)) 0 F(x,y,z(x,y))0 🧠 目标: 求 ∂ z ∂ x \frac{\partial z}{\partial x} ∂x∂z、 …...
Qt学习及使用_第1部分_认识Qt---Qt开发基本流程
前言 学以致用,通过QT框架的学习,一边实践,一边探索编程的方方面面. 参考书:<Qt 6 C开发指南>(以下称"本书") 标识说明:概念用粗体倾斜.重点内容用(加粗黑体)---重点内容(红字)---重点内容(加粗红字), 本书原话内容用深蓝色标识,比较重要的内容用加粗倾…...