当前位置: 首页 > news >正文

【排序】——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&#xff0c;一般是最左边或是最右边的。 2、定义一个begin和一个end&#xff0c;begin从左向右走&#xff0c;end从右向左走。&#xff08;需要注意的是&#xff1a;若选择最左边的数据作为key&#xff0c;则…...

AnaTraf | 网络分析系统:高效IT运维工具

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

踩坑日记:线上接口超时问题排查

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

C语言中的段错误(Segmentation Fault):底层原理及解决方法

引言 在C语言编程中&#xff0c;“段错误”&#xff08;通常由操作系统信号 SIGSEGV 触发&#xff09;是一种常见的异常情况&#xff0c;它表明程序试图访问不受保护的内存区域。本文将深入探讨段错误的原因、底层原理、常见情况以及如何调试和解决这类错误。 段错误的定义 …...

1.两数之和 暴力枚举和暴力搜索法

1. 两数之和 已解答 简单 相关标签 相关企业 提示 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案&#xff0c;并且你不能使用两次相…...

你的收入达到了缴纳个人所得税的标准了吗?

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

【C++贪心】2086. 喂食仓鼠的最小食物桶数|1622

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

notepad++中实现代码整体缩进和退格

我 | 在这里 ⭐ 全栈开发攻城狮、全网10W粉丝、2022博客之星后端领域Top1、专家博主。 &#x1f393;擅长 指导毕设 | 论文指导 | 系统开发 | 毕业答辩 | 系统讲解等。已指导60位同学顺利毕业 ✈️个人公众号&#xff1a;乡下小哥编程。回复 Java全套视频教程 或 前端全套视频教…...

如何调整配置请款单上的立账条件

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

骨传导耳机精选:2024最佳骨传导耳机有哪些?分享骨传导耳机top5

随着健康意识的普及&#xff0c;越来越多的人开始注重运动健身&#xff0c;并将音乐作为运动时的重要伴侣。然而&#xff0c;传统耳机在运动时易脱落且不易清洁的问题&#xff0c;给健身爱好者们带来了不少困扰。幸运的是&#xff0c;骨传导耳机的出现为这一问题提供了解决方案…...

for循环与webAPI练习题

爱太容易了&#xff0c;让爱维持才是最困难的部分 文章目录 for循环练习题webAPI练习题 for循环练习题 练习1&#xff1a;计算1-100的和 let sum 0for (let i 1; i < 100; i) {sum i}console.log(sum)练习2&#xff1a;将1-100之间所有是6的倍数的数字输出到控制台 for …...

FLUX | 轻松掌握FLUX.1 LoRA本地训练秘籍!

在数字艺术和创意领域&#xff0c;FLUX以其独特的虚实结合技术&#xff0c;已经成为艺术家和设计师们手中的利器。今天&#xff0c;我们激动地宣布&#xff0c;FLUX推出了一款全新的FLUX.1版本&#xff0c;它将LoRA本地训练技术完美融合&#xff0c;为用户提供了更加便捷和高效…...

LeetCode 每日一题 最小元素和最大元素的最小平均值

最小元素和最大元素的最小平均值 你有一个初始为空的浮点数数组 averages。另给你一个包含 n 个整数的数组 nums&#xff0c;其中 n 为偶数。 你需要重复以下步骤 n / 2 次&#xff1a; 从 nums 中移除 最小 的元素 minElement 和 最大 的元素 maxElement。 将 (minElement ma…...

PHP学习记录-编辑器推荐和本地环境的安装

文章目录 一&#xff0c;编辑器首推VSCode1&#xff0c;vscode2&#xff0c;PHPStorm 二&#xff0c;PHP环境搭建1&#xff0c;下载安装2&#xff0c;使用phpstudy创建站点3&#xff0c;答疑解惑 一&#xff0c;编辑器首推VSCode 1&#xff0c;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服务&#xff0c;为APP提供更方便的功能&#xff1b;数据库服务器可以存储APP数据&#xff0c;访问更快、更安全&#xff1b;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后台控制端校验-表单验证深度分析与实战优化

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

Codeforces Round 770 (Div. 2)

比赛链接&#xff1a;Dashboard - Codeforces Round 770 (Div. 2) - Codeforces A. Reverse and Concatenate 题意&#xff1a; 思路&#xff1a; 假设 s "abba" 经过1次操作后 -> "abbaabba" s "abcd" 经过一次操作后 -> "abcd…...

ProteinMPNN中蛋白质特征提取

函数 featurize 的主要作用是将一批蛋白质序列和结构信息转化为深度学习模型可以接受的特征矩阵。它在处理蛋白质多链结构(即多个链的蛋白质复合体)时,考虑了可见链和被掩码链的区分。 代码: import torch import numpy as np import csv import time import os import r…...

Docker 离线安装指南

参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性&#xff0c;不同版本的Docker对内核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本&#xff0c;Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...

数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !

我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...

【深度学习新浪潮】什么是credit assignment problem?

Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...