【数据结构与算法】快速排序的优化
创始人
2025-05-31 09:38:55

中心比较值优化、小规模直接插入排序优化、并行优化


前言

快速排序是一种比较优秀的排序算法,然而从快排的原理下手,我们能够对快速排序进一步优化。可以从中心值的选取、小规模直接插入排序、并行优化处理。

中心值优化:通过在样本(前中后)中选取中间值,来尽可能地选择离中位数最近的基准值。

小规模排序:待排序序列较小时,可以通过转变为例如直接插入排序来进行优化,避免深度递归。

并行优化:依据快速排序特点,子序列进行并行快速排序来优化提速


一、优化思路

1.1 中心值选取优化

        快速排序算法的原理,是选取一个中心值,将比它大/小的元素归为一边,一轮即可确定一个元素的位置。最坏情况下,对n个元素分类,可以分为n-1与1,算法复杂度O(n2)。最优情况下,对n个元素分类,可以分为n/2与n/2,或者(n-1)/2与(n-1)/2+1。算法复杂度为O(nlogn)。可见,中心值的选取对于算法的性能提升是非常重要的。

        如何寻找到中心值呢?理想情况下中值是最优的中心值——但是需要通过排序来寻找——这就陷入了自证的怪圈中。不过我们并不苛求极致的优化——有时候的苛求优化的操作只会将问题复杂化。通过“随机”选取部分值,在样本中选择最优的中心值,相比于从第一个开始作中心值的做法,已经是有了极大的优化。

1.2 直接插入排序优化

        快速排序算法每次能够将序列分化为两部分,递归地进行求解。然而,调用函数本身需要占用空间,也耗费时间。当规模较小时,采用在该情况下更优的排序算法,是一种权衡——总是在各种条件下,用最好的方法——符合贪心的要求。

1.3 并行处理

       快速排序最优也是O(nlogn)的复杂度,其他算法例如归并排序也是O(nlogn)的复杂度,快速排序有一个非常重要的特征。每一轮分类,都将数据分为两个部分,这两个部分彼此排序互不影响,因此可以并行地实现。

二、实验结果

实验结果

数据规模为100的排序对比:

因为优化过后速度过快,时间记录为0,因此效率得到一个无穷大。(/0)

数据规模为10,0000的排序对比:(均显示前100个数)

        可以看到,数量级为100000已经非常庞大了,对于计算机而言,使用快速排序算法,速度还是很快的,而且优化效率几乎达到一倍。

数据规模为1,0000,0000的排序对比:(均显示前100个数)

         在面对亿级的数据时,优化过的算法效率提升非常可观。

三、优化源码

中心值选取优化 

// ****************************************************************************************// optimized point 1: // compare the first, last and middle one, swap the middle value recond with the first location int middle=(i+j)/2;int index=(A[low]>=A[high] && A[low]<=A[middle])?low:((A[high]>=A[low] && A[high]<=A[middle])?high:middle);swap(A[index],A[low]);
//*****************************************************************************************

采取抽样的方法,前中后选取中间值。离散选取减小了因部分连续片段同时较大或较小而所选中间值偏大或偏小的可能性。

直接插入排序优化

 //****************************************************************************************// optimized opint 2:// if the size of array to be sorted is small enough, // direct-insert-sort is much more efficient than quickSort if(high-lowtemp&&j>=low){A[j+1]=A[j];j--;}A[j+1]=temp;}return;}
//*****************************************************************************************

当数据规模足够小时(

并行优化排序

(这部分花了两天,并行在vscode要配置的东西和注意的事项太多了,一不小心就出错;此外,一股脑儿在递归函数里面用多线程,效率嘎嘎降,100000000个数据,不加判断就一个劲儿多线程,可以在80s左右完成。。。是不优化的6/7倍)

// ****************************************************************************************
// optimized point 3:
// via openmp, make it runs parallelly
//
// Actually, there are 2 options with different parallelly running structure as follows
//***********************option 1*********************************/// if(depth<=7)// {//     #pragma omp parallel  // starts a new team//     {//         #pragma omp sections//         {//             //{ Work1(); }//             #pragma omp section//             { QuickSort_optimized(A, i+1, high, depth+1); }//             #pragma omp section//             { QuickSort_optimized(A, low, j-1, depth+1); }//         }//     }// }// else// {//     QuickSort_optimized(A, i+1, high, depth+1);//     QuickSort_optimized(A, low, j-1, depth+1);// }
//***********************option 2*********************************/if(depth<=7){#pragma omp parallel num_threads(2){#pragma omp single{#pragma omp taskQuickSort_optimized(A, i+1, high, depth+1);#pragma omp taskQuickSort_optimized(A, low, j-1, depth+1);#pragma omp taskwait}}}else{QuickSort_optimized(A, i+1, high, depth+1);QuickSort_optimized(A, low, j-1, depth+1);}
}
//**************************************************************************************

值得说明的是,如果直接无脑用并行子部分排序,由于快速排序是的递归函数,每一次并行都会产生两个线程。首先就是线程随着递归深度以指数爆炸的方式产生。其次,线程之间处理也随着线程的增多而发生冲突,产生意想不到的拖延“死锁”。再次,众多线程的创建、运维、消除的声明周期,同样占用着大量的时间与资源。因此,这里采用浅层并行,深层串行的方式,着重凸显线程并发的优势,规避其劣势。


总结

除了上述三种优化方法,还有如尾预编译等优化手段,可以查阅其他大牛的博客。

需要基础快排/优化快排源代码的,可以评论区喊我。

一起学习,一起加油!

相关内容

热门资讯

天干地支(Java) 题目描述 古代中国使用天干地支来记录当前的年份。 天干一共有十个,分别为:...
SpringBoot雪花ID长... Long类型精度丢失 最近项目中使用雪花ID作为主键,雪花ID是19位Long类型数...
对JSP文件的理解 JSP是java程序。(JSP本质还是一个Servlet) JSP是&#...
【03173】2021年4月高... 一、单向填空题1、大量应用软件开发工具,开始于A、20世纪70年代B、20世纪 80年...
LeetCode5.最长回文子... 目录题目链接题目分析解题思路暴力中心向两边拓展搜索 题目链接 链接 题目分析 简单来说࿰...
unity的C#学习——浮点常... 浮点常量 在C#中,一个浮点常量是由整数部分、小数点、小数部分和指数部分组成。浮点常量...
Angular 开发NPM第三... 准备工作 首先已经安装过node以及angular以及注册过npm账号 新建项目 ng new ...
【Linux Manpage】... NAME libi2c - publicly accessible functions provid...
Attention Is Al... Transformer摘要引言相关工作模型架构结论 摘要 当前主流的序列转录模型,主要...
Unity的闪屏Logo去除、... 先上最终方案链接,想自己学习的朋友可以直接去学,我的博客主要针对安卓VR...
大佬学习经验分享 -Java业... 大佬学习经验分享 大佬工作这些年来,经常会有同学来找大佬沟通学习和成长,...
flink sql 如何ups... Flink Table 的三种 Sink 模式 作为计算引擎 Flink 应用的计算结果总要以某种方...
使用SuperMap iSer... 由于iServer和iObjectsJava需要依赖许多第三方软件才能在linux环境下运行。官方给...
线性回归-线性神经网络 线性神经网络 注: 该文章为作者学习深度学习笔记,共参考以下两大开源深度学习资料: 深度学习(花书...
【算法题】2191. 将杂乱无... 题目: 给你一个下标从 0 开始的整数数组 mapping ,它表示一个...
STM32的中断 目录 一、STM32中断概述 二、外部中断控制器EXTI 三、按键中断 四、串口中断 一、STM3...
拼多多发布财报:业绩大增 略低... 3月20日,美股盘前,拼多多发布了2022年第四季度财报,...
阿里巴巴2017实习生笔试题(... 具体题目来自阿里巴巴2017实习生笔试题,本文仅为整理与汇总。 本题应该往C+...
qq怎么安装不了(QQ怎么都安... qq怎么安装不了(QQ怎么都安装不上重装也不行,是哪里出了问题?) 一、...
Linux内核进程管理六种状态 进程概念1)正在执行的程序2)正在计算机上执行的程序实例3)...
threejs与六轴机械臂联动... threejs与六轴机械臂联动思路 六轴机械臂的数据格式 如何将这种数据格式的数据与threej...
Postman接口与压力测试实... Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件。它提供功能强大的 W...
shiro架构认证 -Shir... 一、权限的管理 1.1 什么是权限管理 基本上涉及到用户参与的系统都要进行权限管理,权...
DC:2靶机 通关详解 信息收集 开放80端口 访问看看 发现访问不了,回去看了一眼介绍 要手动改一下hosts 现...
20230322整理 1.什么是SpringCloud? Spring Cloud是一系列框架的有序集合。它...
刷题(二) 目录标题题目列表第一题解析方法1:递归方法2:迭代第二题解析解法一&#x...
Day924.自动化测试 -系... 自动化测试 Hi,我是阿昌,今天学习记录的是关于自动化测试的内容。 自动...
黑马程序员 Redis 踩坑及... 文章目录p30 短信登录-隐藏用户敏感信息p50 优惠券秒杀-添加优惠券p69 秒杀优化-异步秒杀思...
耐克阿迪颓势之下,增势向好的特... 每一年的财报季,都是观察各运动鞋服品牌的最佳窗口。3月22日,特步集团发...
多线程之线程安全 - java... 前言 本篇通过了解线程不安全产生的原因,解决线程不安全的方式,一般出现线...