分治算法(2)_快速排序_排序数组

个人主页:C++忠实粉丝
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C++忠实粉丝 原创

分治算法(2)_快速排序_排序数组

收录于专栏【经典算法练习】
本专栏旨在分享学习算法的一点学习笔记,欢迎大家在评论区交流讨论💌

目录

温馨提示:

1. 快速排序简介:

原理:

时空复杂度分析:

优缺点:

2. 题目链接:

3. 题目描述:

4. 解法(快速排序)

快速排序算法思路:

快速排序的缺点;

1. 数组有序或重复效率低

2. 对于较小规模的数据,快速排序可能不如插入排序高效

快速排序的优化:

1. 随机取key

2. 数组分三块  

代码展示:

结果分析: 


温馨提示:

这里并不会对快速排序进行详细讲解,只会对它的思想进行解释,如果大家想看详细讲解版的,可以去下面博客查看:

排序算法(4)之快速排序(1)-CSDN博客

1. 快速排序简介:

原理:

选择基准:从待排序的数组中选择一个元素作为“基准”(Pivot),通常可以选择第一个元素、最后一个元素或随机选择。

分区:将数组中的其他元素根据基准值进行分区。所有小于基准值的元素移动到基准值的左侧,所有大于基准值的元素移动到右侧。这样,基准值的最终位置就确定了。

递归排序:对基准值左侧和右侧的两个子数组递归进行快速排序。

合并结果:由于子数组已经排序完毕,因此只需要将它们与基准值组合在一起即可。

时空复杂度分析:

时间复杂度
平均时间复杂度:O(n log n)
最坏时间复杂度:O(n²),通常发生在选择的基准值极端不平衡时(例如,已经排好序的数组)。
最佳时间复杂度:O(n log n)
空间复杂度
快速排序的空间复杂度为O(log n),因为递归调用的深度为O(log n)。它是一种原地排序算法,不需要额外的存储空间。 

优缺点:

 优点:

平均情况下性能优异。
原地排序,节省空间。
可以选择不同的基准选择策略以优化性能。
缺点:

最坏情况下的时间复杂度较高。
对于较小规模的数据,快速排序可能不如插入排序高效。

2. 题目链接:

OJ链接 : 排序数组

3. 题目描述:

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

你必须在 不使用任何内置函数 的情况下解决问题,时间复杂度为 O(nlog(n)),并且空间复杂度尽可能小。

示例 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 * 104
  • -5 * 104 <= nums[i] <= 5 * 104

4. 解法(快速排序)

快速排序算法思路:

1. 选择基准值: 通常选择数组的第一个元素作为基准值,也可以随机选择数组中的某个元素。

2. 划分过程: 使用两个指针,一个从左边开始(左指针),一个从右边开始(右指针)。它们分别向中间移动,直到找到需要交换的元素。

3. 具体步骤:

        i. 左指针移动: 从左往右找到第一个大于或等于基准值的元素。
        ii. 右指针移动: 从右往左找到第一个小于或等于基准值的元素。
        iii. 交换元素: 如果左指针所指元素大于基准值,并且右指针所指元素小于基准值,则交换这两个元素。
        iv. 继续移动指针: 继续移动左右指针,直到它们相遇。
4. 交换基准值: 最后将基准值与右指针所指的元素进行交换,使得基准值左侧的元素都小于或等于基准值,右侧的元素都大于或等于基准值。

// 假设按照升序对array数组中[left, right)区间中的元素进行排序
void QuickSort(int array[], int left, int right)
{if (right - left <= 1)return;// 按照基准值对array数组的 [left, right)区间中的元素进行划分int div = partion(array, left, right);
}
// 划分成功后以div为边界形成了左右两部分 [left, div) 和 [div+1, right)
// 递归排[left, div)
QuickSort(array, left, div);
// 递归排[div+1, right)
QuickSort(array, div + 1, right);
class Solution {
public:vector<int> sortArray(vector<int>& nums) {qsort(nums, 0, nums.size() - 1);return nums;}void qsort(vector<int>& arr, int left, int right){if(left >= right) return;int key = left;int begin = left;int end = right;while(begin < end){while(begin < end && arr[end] >= arr[key]) end--;while(begin < end && arr[begin] <= arr[key]) begin++;swap(arr[begin], arr[end]);}swap(arr[key], arr[begin]);key = begin;//[left, key - 1][key][key + 1, right]qsort(arr, left, key - 1), qsort(arr, key + 1, right);}
};

 

快速排序的缺点;

1. 数组有序或重复效率低

当数组有序时,如果key还是取数组中第一个值得话,快排得递归深度就退化为O(N),整体的时间复杂度就退化为O(N^2)

2. 对于较小规模的数据,快速排序可能不如插入排序高效

对于较小的数据集,快速排序的递归深度可能较高,每次递归调用都会消耗额外的栈空间,这在小规模数据上显得不够高效。 

快速排序的优化:

1. 随机取key

因为key取数组第一个数或者最后都会在数组有序中效率退化,所以我们可以直接取随机值,这样我们的递归深度是接近O(logN)--详细证明大家可以去看算法导论 

class Solution {
public:vector<int> sortArray(vector<int>& nums) {qsort(nums, 0, nums.size() - 1);return nums;}void qsort(vector<int>& arr, int left, int right){if(left >= right) return;int key = left;int begin = left;int end = right;while(begin < end){while(begin < end && arr[end] >= arr[key]) end--;while(begin < end && arr[begin] <= arr[key]) begin++;swap(arr[begin], arr[end]);}swap(arr[key], arr[begin]);key = begin;//[left, key - 1][key][key + 1, right]qsort(arr, left, key - 1), qsort(arr, key + 1, right);}
};

可以看到这一次通过了19个例子,卡在一个超长的连续数组, 因为这样无论怎么随机,取到的数都相同,递归深度退化为O(N),需要我们使用数组分成三块来解决!

2. 数组分三块  

我们直接将数组分成三块 : 小于key, 等于key, 大于key.这样我们再遇到上次的超长重复数组,我们可以直接以O(1)的时间复杂度解决它

算法思路:  

1. 定义递归出口

2. 利用随机选择基准函数生成一个基准元素

3. 将数组分成三个区域

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 i = l, left = l - 1, right = r + 1;while(i < right){if(nums[i] < key) swap(nums[++left], nums[i++]);else if(nums[i] == key) i++;else swap(nums[--right], nums[i]);}qsort(nums, l, left), qsort(nums, right, r);}int getRandom(vector<int>& nums, int left, int right){int r = rand();return nums[left + r % (right - left + 1)];}
};

结果分析: 

经过改良后的快排能过顺利通过!!!并且效率还很不错!!!

最重要的的是代码只有不到30行,大家可以作为模板

这里不得不吐槽一下官方提供的快速排序解法通过不了的问题,总之这个快排算法很优秀! 

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

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

相关文章

消息称苹果iPhone系列将完全放弃LCD屏幕

近日&#xff0c;据日经亚洲消息&#xff0c;苹果公司将于明年初推出搭载OLED显示屏的 iPhone SE 4&#xff0c;标志其整个iPhone系列已进入从 LCD 过渡到 OLED 技术的最后阶段&#xff0c;2025年及之后销售的所有iPhone机型均将搭载OLED屏幕。 由此&#xff0c;两家日本面板供…

【STM32开发环境搭建】-4-在STM32CubeMX中新增Keil(MDK-ARM) 5的工程目录(包含指定路径的C和H文件)

案例背景&#xff1a; 由于Keil(MDK-ARM)5工程&#xff1a;DEMO_STM32F030C8T6.uvprojx是由STM32CubeMX工具生成的&#xff0c;如果我们在Keil工程中手动添加了一些c文件和h文件的Include Path包含路径&#xff0c;会在STM32CubeMX下一次生成uvprojx文件时&#xff0c;被删除&…

【韩顺平Java笔记】第8章:面向对象编程(中级部分)【272-284】

272. 包基本介绍 272.1 看一个应用场景 272.2 包的三大作用 272.3 包的基本语法 273. 包原理 274. 包快速入门 在不同的包下面创建不同的Dog类 275. 包命名 276. 常用的包 一个包下,包含很多的类,java 中常用的包有: java.lang.* //lang 包是基本包&#xff0c;默认引入&…

hdfs伪分布式集群搭建

1 准备 vmware 虚拟三台centos系统的节点三台机器安装好jdk环境关闭防火墙&#xff08;端口太多&#xff0c;需要的自行去开关端口&#xff09;hadoop压缩包解压至三台服务器 可在一台节点上配置完成后克隆为三台节点 2 host修改 vi /etc/hosts在每个节点上添加三台机器的i…

linux部署NFS和autofs自动挂载

目录 &#xff08;一&#xff09;NFS&#xff1a; 1. 什么是NFS 2. NFS守护进程 3. RPC服务 4. 原理 5. 部署 5.1 安装NFS服务 5.2 配置防火墙 5.3 创建服务端共享目录 5.4 修改服务端配置文件 (1). /etc/exports (2). nfs.conf 5.5 启动nfs并加入自启 5.6 客户端…

求矩阵的鞍点

题目&#xff1a;求一个矩阵的鞍点&#xff0c;即行上最小而列上最大的元素。 代码&#xff1a;&#xff08;多个最小值认为第一个为最小&#xff0c;更严谨的代码在最后&#xff09; #include<iostream> #include<time.h> using namespace std;int main(){int n…

【Qt】控件概述(7)—— 布局管理器

布局管理器 1. 布局管理器2. QVBoxLayout——垂直布局3. QHBoxLayout——水平布局4. QGridLayout——网格布局5. QFormLayout——表单布局6. QSpacer 1. 布局管理器 在我们之前值ui界面进行拖拽设置控件时&#xff0c;都是通过手动的控制控件的位置的。同时每个控件的位置都是…

贪心算法c++

贪心算法C概述 一、贪心算法的基本概念 贪心算法&#xff08;Greedy Algorithm&#xff09;&#xff0c;又名贪婪法&#xff0c;是一种解决优化问题的常用算法。其基本思想是在问题的每个决策阶段&#xff0c;都选择当前看起来最优的选择&#xff0c;即贪心地做出局部最优的决…

实验OSPF路由协议(课内实验)

实验1&#xff1a;OSPF路由协议 实验目的及要求&#xff1a; 通过实验&#xff0c;能够理解链路状态型路由协议OSPF协议的工作原理&#xff0c;掌握如何实现单区域 OSPFv2配置指令&#xff0c;能够熟练的应用各种OSPF协议相关的配置指令完善网络设计。掌握验证OSPFv2网络连接…

Linux启动mysql报错

甲方公司意外停电&#xff0c;所有服务器重启后&#xff0c;发现部署在Linux上的mysql数据库启动失败.再加上老员工离职&#xff0c;新接手项目&#xff0c;对Linux系统了解不多&#xff0c;解决起来用时较多&#xff0c;特此记录。 1.启动及报错 1.1 启动语句1 启动语句1&a…

利用 OpenAI 和 Python 预测股市行情

作者:老余捞鱼 原创不易,转载请标明出处及原作者。 写在前面的话: 本文介绍了如何利用 OpenAI 和 Python 进行股市情绪预测。主要通过使用 EODHD 提供的股市和金融新闻 API 来提取新闻数据,并利用 LangChain 和 OpenAI 的大型语言模型进行情感分析。 一、综述 …

Eureka的搭建、注册和拉取

目录 搭建 动手实践 搭建EurekaServer 创建项目 编写启动类 添加application.yml文件 启动EurekaApplication ​编辑 总结 搭建EurekaServer 注册 将user-service服务注册到EurekaServer 将order-service服务注册到EurekaServer 重启order-service和user-service…

将自己写好的项目部署在自己的云服务器上

准备工作 这里呢我要下载的终端软件是Xshell 如图&#xff1a; 自己准备好服务器&#xff0c;我这里的是阿里云的服务器&#xff0c; 如图&#xff1a; 这两个准备好之后呢&#xff0c;然后对我们的项目进行打包。 如图&#xff1a; 这里双击打包就行了。 找到自己打成jar包…

Linux shell编程学习笔记85:fold命令——让文件瘦身塑形显示

0 引言 我们使用的电脑屏幕有宽有窄&#xff0c;我们有时候希望文件能按照我们的屏幕宽度来调整和匹配&#xff0c;这时我们可以使用fold命令。 1 fold命令 的帮助信息、功能、命令格式、选项和参数说明 1.1 fold 命令 的帮助信息 我们可以输入命令 fold--help 来查看fold …

[uni-app]小兔鲜-08云开发

uniCloud可以通过JS开发服务端,包含云数据库, 云函数, 云存储等功能, uniCloud可结合 uni-ui 组件库使用 效果展示: <picker>城市选择组件不支持h5端和APP端, 所以我们使用 <uni-data-picker>组件进行兼容处理 <uni-data-picker>的数据使用云数据库的数据 云…

Docker安装及使用记录

本文汇总一下 Docker 的安装过程和使用过程中的问题 安装过程 Windows Linux 更新软件源&#xff1a;Linux安装前可先更新以下各自发行版包管理器的软件源 卸载旧版本&#xff1a;如果之前安装过的话&#xff0c;可以先卸载 yum remove docker docker-common docker-sel…

Study-Oracle-10-ORALCE19C-RAC集群维护

一路走来,所有遇到的人,帮助过我的、伤害过我的都是朋友,没有一个是敌人。 一、RAC的逻辑架构与进程 1、RAC 与单实例进程的对比 2、RAC相关进程功能 3、在主机查看RAC后台进程 快捷键设置 alias sqlplus=rlwrap sqlplus alias rman=rlwrap rman alias crsctl=/u01/app…

Android Automotive(一)

目录 什么是Android Automotive Android Automotive & Android Android Automotive 与 Android Auto 什么是Android Automotive Android Automotive 是一个基础的 Android 平台,它能够运行预装的车载信息娱乐系统(IVI)应用程序,以及可选的二方和三方 Android 应用程…

C(十五)函数综合(一)--- 开公司吗?

在这篇文章中&#xff0c;杰哥将带大家 “开公司”。 主干内容部分&#xff08;你将收获&#xff09;&#xff1a;&#x1f449; 为什么要有函数&#xff1f;函数有哪些&#xff1f;怎么自定义函数以及获得函数的使用权&#xff1f;怎么对函数进行传参&#xff1f;函数中变量的…

Python和R及Julia妊娠相关疾病生物剖析算法

&#x1f3af;要点 算法使用了矢量投影、现代优化线性代数、空间分区技术和大数据编程利用相应向量空间中标量积和欧几里得距离的紧密关系来计算使用妊娠相关疾病&#xff08;先兆子痫&#xff09;、健康妊娠和癌症测试算法模型使用相关性投影利用相关性和欧几里得距离之间的关…