【cpp】快速排序优化

标题:【cpp】快速排序

@水墨不写bug


正文开始:

 快速排序的局限性:

虽然快速排序是一种高效的排序算法,但也存在一些局限性:

  1. 最坏情况下的时间复杂度:如果选择的基准元素不合适,或者数组中存在大量重复的元素,快速排序的时间复杂度可能退化为O(n^2)。这种情况发生在每次划分之后,基准元素都是当前子数组中的最小或最大元素。

  2. 对于小规模数据的排序效果较差:当数组规模较小时,例如只有几个元素,快速排序的性能可能不如其他简单的排序算法,如插入排序或选择排序。

  3. 对于有序数组的排序效果较差:如果待排序的数组已经接近有序,快速排序的性能会下降。因为在划分过程中,基准元素的选择可能会导致子数组的不平衡,使得算法执行的时间增加。

  4. 快速排序是一种不稳定的排序算法:当原始数组中存在相等元素时,算法执行过程中可能会改变它们的相对顺序。

        如何优化重复元素的问题,以免快排的时间复杂度退化为O(N^2)?

        通过下面这一问题,我们或许会得到一些启发。 

(一)颜色分类(leetcode)

        给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

        我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

        必须在不使用库内置的 sort 函数的情况下解决这个问题。

示例 1:

输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]

示例 2:

输入:nums = [2,0,1]
输出:[0,1,2]

提示:

  • n == nums.length
  • 1 <= n <= 300
  • nums[i] 为 01 或 2

进阶:

  • 你能想出一个仅使用常数空间的一趟扫描算法吗?

        颜色分类思想:

        定义三个指针(left,cur,right):

        在排序过程中,这三个指针(left,cur,right),将数组分为四个部分,接下来希望你拿出纸笔跟我一起画一下:

        四个部分:

        一:【0,left】 

        二:【left+1,cur-1】 

        三:【cur,right-1】 

        四:【right,len-1】  

主体思路是:

        cur向后遍历,将小于1的元素放在left左边,等于1的元素不变位置,大于1的元素放在right的右边。

        需要注意的细节是,对于(nums[cur] == 0 )由于left是右闭区间,其指向的元素满足要求,所以要先自增再交换;交换之后cur++向后遍历。

        对于(nums[cur] == 1)cur直接向后遍历;

        对于(nums[cur] == 2)由于left是左闭区间,其指向的元素满足要求,所以要先自减再交换;right在交换之前指向的元素本身就是未遍历的元素,所以交换之后不需要cur自增,直接判断cur交换得到的未遍历的元素即可。

        

class Solution {
public:void sortColors(vector<int>& nums) {int n = nums.size();for(int left = -1,right = n,cur = 0;cur < right;){if(nums[cur] == 0) swap(nums[++left],nums[cur++]);else if(nums[cur] == 1) cur++;else swap(nums[--right],nums[cur]);}}
};

(二)排序数组(leetcode)

        给你一个整数数组 nums,请你将该数组升序排列。

示例 1:

输入:nums = [5,2,3,1]
输出:[1,2,3,5]

示例 2:

输入:nums = [5,1,1,2,0,0]
输出:[0,0,1,1,2,5]

提示:

  • 1 <= nums.length <= 5 * 10^4
  • -5 * 10^4 <= nums[i] <= 5 * 10^4

        根据颜色分类的主体思想,如果用颜色分类来优化快排,那么这时再出现大量重复元素,就可以一次将他们排好序,不会再出现 在每次划分之后,基准元素都是当前子数组中的最小或最大元素的情况。

class Solution {
public:vector<int> sortArray(vector<int>& nums) {srand(time(NULL));qsort(nums,0,nums.size()-1);return nums;}void qsort(vector<int>& nums,int l,int r){//递归出口if(l >= r) return;//数组分三块int key = GetRandom(nums,l,r);int cur = l,left = l-1,right = r+1;while(cur < right){if(nums[cur] < key) swap(nums[++left],nums[cur++]);else if(nums[cur] == key) cur++;else swap(nums[--right],nums[cur]); }//递归排序子区间qsort(nums,l,left);qsort(nums,right,r);}int GetRandom(vector<int>& nums,int left,int right){int r = rand();return nums[ r % ( right - left + 1 ) + left];}
};

代码理解: 

         上述代码是用C++实现的快速排序算法,用于对一个整数数组进行排序。sortArray函数接收一个输入向量nums,并使用qsort函数对其进行排序。

1.函数参数

qsort函数是一个递归函数,用于执行快速排序算法。它接收三个参数:输入向量nums、左边界索引l和右边界索引r

2.递归出口的定义

        函数有一个基本情况,即如果左边界索引大于或等于右边界索引,那么只有一个元素或没有元素需要排序,所以函数返回。

3.key的选取

        使用GetRandom函数选择一个随机的轴元素(key),该函数在当前分区的范围内生成一个随机的索引。

4.递归主体

        然后,函数将数组分为三部分:小于轴元素(key)的元素、等于轴元素(key)的元素和大于轴元素(key)的元素。它使用三个指针:curleftright

cur指针从左边界索引开始,向右边界索引移动,并相应地交换元素。如果当前元素小于轴元素,则将其与left指针处的元素交换,并同时递增这两个指针。如果当前元素等于轴元素,则递增cur指针。如果当前元素大于轴元素,则将其与right指针处的元素交换,并递减right指针。

        分区完成后,函数在左子数组和右子数组上递归调用自身以进行排序。

5.GetRandom函数

GetRandom函数在给定的左边界和右边界索引范围内生成一个随机的索引。它使用rand函数生成一个随机数,然后通过对右边界和左边界索引之间的差值加一取模,并加上左边界索引来计算索引值。

6.sortArray函数

        最后,在sortArray函数中,在开始排序过程之前,调用srand函数以用当前时间初始化随机数生成器,以确保每次运行程序时都会生成不同的随机数。

然后返回排序后的数组。


完~

未经作者同意禁止转载

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

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

相关文章

插入代码---四

文章目录 在空白节插入代码构造恶意代码计算函数相对地址修改入口地址返回原地址 扩大节新增节 对与一个程序我们需要在里面添加自己的功能&#xff0c;让程序增加一些我们的函数&#xff0c;那么我们就需要了解PE文件结构&#xff0c;然后对其进行修改&#xff0c;这里我们将基…

位运算-191. 位1的个数- 136. 只出现一次的数字

位1的个数 已解答 简单 相关标签 相关企业 编写一个函数&#xff0c;输入是一个无符号整数&#xff08;以二进制串的形式&#xff09;&#xff0c;返回其二进制表达式中 设置位 的个数&#xff08;也被称为汉明重量&#xff09;。 示例 1&#xff1a; 输入&#xff1a;n 11 输…

SpringBoot+ECharts+Html 地图案例详解

1. 技术点 SpringBoot、MyBatis、thymeleaf、MySQL、ECharts 等 此案例使用的地图是在ECharts社区中查找的&#xff1a;makeapie echarts社区图表可视化案例 2. 准备条件 在mysql中创建数据库echartsdb&#xff0c;数据库中创建表t_location_count表&#xff0c;表中设置两个…

能耗监测管理系统与技术方案

能耗监测管理系统是目前能源管理中重要的技术手段&#xff0c;它通过集成现代监测技术和信息技术&#xff0c;实现对能源消耗的实时监控、数据分析和决策支持&#xff0c;帮助企业或机构实现能源的高效管理和节能降耗。本篇文章将从能耗监测管理系统的组成、关键技术、应用领域…

ubuntu-server部署hive-part1-安装jdk

参照 https://blog.csdn.net/qq_41946216/article/details/134345137 操作系统版本&#xff1a;ubuntu-server-22.04.3 虚拟机&#xff1a;virtualbox7.0 安装jdk 上传解压 以root用户&#xff0c;将jdk上传至/opt目录下 tar zxvf jdk-8u271-linux-x64.tar.gz 配置环境变量…

嵌入式Qt QGridLayout网格布局管理器

一.QGridLayout网格布局管理器 //以行为单位 设置比例系数 void QGridLayout::setRowStretch ( int row, int stretch ) //以列为单位 设置比例系数 void QGridLayout::setColumnStretch ( int column, int stretch ) 实验&#xff1a; Widget.h&#xff1a; #ifndef _WIDGE…

Redis安装说明

Redis安装说明 大多数企业都是基于Linux服务器来部署项目&#xff0c;而且Redis官方也没有提供Windows版本的安装包。因此课程中我们会基于Linux系统来安装Redis. 此处选择的Linux版本为CentOS 7. Redis的官方网站地址&#xff1a;https://redis.io/ 1.单机安装Redis 1.1.…

2024.4.3-[作业记录]-day08-CSS 盒子模型(溢出显示、伪元素)

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 作业 2024.4.3-学习笔记css溢出显示单行文本溢出显示省略号多行文本溢出显示省…

【css】使用display:inline-block后,元素间存在4px的间隔

问题&#xff1a;在本地项目中使用【display: inline-block】&#xff0c;元素间存在4px间隔。打包后发布到外网又不存在这个问题了。 归根结底这是一个西文排版的问题&#xff0c;英文有空格作为词分界&#xff0c;而中文则没有。 此时的元素具有文本属性&#xff0c;只要标签…

电商技术揭秘七:搜索引擎中的SEO关键词策略与内容优化技术

文章目录 引言一、关键词策略1.1 关键词研究与选择1. 确定目标受众2. 使用关键词研究工具3. 分析搜索量和竞争程度4. 考虑长尾关键词5. 关键词的商业意图6. 创建关键词列表7. 持续监控和调整 1.2 关键词布局与密度1. 关键词自然分布2. 标题标签的使用3. 首次段落的重要性4. 关键…

Linux第4课 Linux的基本操作

文章目录 Linux第4课 Linux的基本操作一、图形界面介绍二、终端界面介绍 Linux第4课 Linux的基本操作 一、图形界面介绍 本节以Ubuntu系统的GUI为例进行说明&#xff0c;Linux其他版本可自行网搜。 图形系统进入后&#xff0c;左侧黄框内为菜单栏&#xff0c;右侧为桌面&…

C++进阶--C++11(2)

C11第一篇 C11是C编程语言的一个版本&#xff0c;于2011年发布。C11引入了许多新特性&#xff0c;为C语言提供了更强大和更现代化的编程能力。 可变参数模板 在C11中&#xff0c;可变参数模板可以定义接受任意数量和类型参数的函数模板或类模板。它可以表示0到任意个数&…

C++之类和对象(上)

目录 1.面向过程和面向对象初步认识 2.类的引入 3.类的定义 4.类的访问限定符及封装 4.1访问限定符 4.2 类的两种定义方式 第一种&#xff1a; 第二种&#xff1a; 4.3封装 5.类的实例化 6.类对象模型 1.面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;…

【Claude 3】This organization has been disabled.此组织已被禁用。(Claude无法对话的原因和解决办法)

Claude对话提示 This organization has been disabled.此组织已被禁用。 This organization has been disabled.此组织已被禁用。 This organization has been disabled.此组织已被禁用。 问题截图 问题原因 出现该页面&#xff0c;表示您的账户已经无法使用&#xff0c;可能…

SQL语言

一、DDL数据库定义语言 1、登录mySQL mysql -u"用户名" -p"密码" -h"登录地址 -h&#xff1a;默认为本机 示例&#xff1a; 2、查看当前存在的数据库 show databases; 示例&#xff1a; 3、创建数据库database create…

约数与倍数-第12届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第45讲。 约数与倍数&#…

非关系型数据库——Redis基本操作

目录 一、Redis数据库常用命令 1.Set——存放数据 2.Get——获取数据 3.Keys——获取符合条件的键值 4.Exists——判断键值是否存在 5.Del——删除指定键值 6.Type——获取键值对应的类型 7.Rename——对已有键值重命名&#xff08;覆盖&#xff09; 8.Renamenx——对…

更高效、更简洁的 SQL 语句编写丨DolphinDB 基于宏变量的元编程模式详解

元编程&#xff08;Metaprogramming&#xff09;指在程序运行时操作或者创建程序的一种编程技术&#xff0c;简而言之就是使用代码编写代码。通过元编程将原本静态的代码通过动态的脚本生成&#xff0c;使程序员可以创建更加灵活的代码以提升编程效率。 在 DolphinDB 中&#…

【智能算法】随机分形搜索算法(SFS)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2015年&#xff0c;Salimi等人受到分形的扩散性质启发&#xff0c;提出了随机分形搜索算法&#xff08;Stochastic Fractal Search &#xff0c;SFS&#xff09;。 2.算法原理 2.1算法思想 SFS通…

《QT实用小工具·十一》Echart图表JS交互之仪表盘

1、概述 源码放在文章末尾 该项目为Echart图表JS交互之炫酷的仪表盘&#xff0c;可以用鼠标实时改变仪表盘的读数。 下面为demo演示&#xff1a; 该项目部分代码如下&#xff1a; #include "widget.h" #include "ui_widget.h" #include "qurl.h&q…