快速排序算法改进:随机快排-荷兰国旗划分详解
随机快速排序-荷兰国旗划分算法详解
- 一、基础知识回顾
- 1.1 快速排序简介
- 1.2 荷兰国旗问题
- 二、随机快排 - 荷兰国旗划分原理
- 2.1 随机化枢轴选择
- 2.2 荷兰国旗划分过程
- 2.3 结合随机快排与荷兰国旗划分
- 三、代码实现
- 3.1 Python实现
- 3.2 Java实现
- 3.3 C++实现
- 四、性能分析
- 4.1 时间复杂度
- 4.2 空间复杂度
- 五、实际应用场景
- 5.1 数据排序与预处理
- 5.2 并行计算与分布式系统
快速排序是经典的平均时间复杂度 O ( n ) O(n) O(n)的排序算法,而随机快排结合荷兰国旗划分(Dutch National Flag Partitioning)的优化策略,进一步提升了性能和稳定性。本文我将深入剖析随机快排 - 荷兰国旗划分的原理、实现细节、性能分析以及实际应用场景,带你全面掌握这一强大的排序技术。
一、基础知识回顾
1.1 快速排序简介
快速排序是一种基于分治思想的排序算法。基本思路是:从数组中选择一个元素作为枢轴(pivot),将数组分为两部分,使得左边部分的元素都小于等于枢轴,右边部分的元素都大于枢轴,然后递归地对左右两部分进行排序,最终实现整个数组的有序排列。快速排序在平均情况下的时间复杂度为 O ( n l o g n ) O(n log n) O(nlogn),但在最坏情况下(如数组已经有序且每次选择第一个或最后一个元素作为枢轴),时间复杂度会退化为 O ( n 2 ) O(n^2) O(n2)。
1.2 荷兰国旗问题
荷兰国旗由红、白、蓝三种颜色的条纹组成,荷兰国旗问题是指:给定一个由红色、白色和蓝色三种颜色的小球组成的数组,要求将数组中的元素按照红、白、蓝的顺序排列,且尽可能地提高排序效率。在算法实现中,用0表示红色,1表示白色,2表示蓝色。荷兰国旗划分算法通过一次遍历,将数组划分为小于枢轴、等于枢轴和大于枢轴的三个区域,这种划分方式为随机快排的优化提供了思路。
二、随机快排 - 荷兰国旗划分原理
2.1 随机化枢轴选择
为了避免快速排序在最坏情况下时间复杂度退化,随机快排采用随机选择枢轴的策略,在每次进行划分操作前,从待排序数组中随机选择一个元素作为枢轴。这样做使得无论输入数组的初始顺序如何,都能在大概率下保证划分的均衡性,算法的平均时间复杂度从而稳定在 O ( n l o g n ) O(n log n) O(nlogn)。
2.2 荷兰国旗划分过程
荷兰国旗划分的核心在于将数组划分为三个区间:
- 小于枢轴区间:位于数组的左侧,包含所有小于枢轴的元素。
- 等于枢轴区间:位于小于枢轴区间和大于枢轴区间之间,包含所有等于枢轴的元素。
- 大于枢轴区间:位于数组的右侧,包含所有大于枢轴的元素。
在划分过程中,使用三个指针:
- left指针:指向小于枢轴区间的右边界,初始位置为数组起始位置 - 1。
- current指针:用于遍历数组,从数组起始位置开始。
- right指针:指向大于枢轴区间的左边界,初始位置为数组末尾位置。
划分过程如下:
- 当
current
指针小于等于right
指针时,进行循环:- 若
arr[current]
小于枢轴,left
指针右移一位,交换arr[left]
和arr[current]
,然后current
指针右移一位。 - 若
arr[current]
等于枢轴,current
指针直接右移一位。 - 若
arr[current]
大于枢轴,交换arr[current]
和arr[right]
,right
指针左移一位。
- 若
- 循环结束后,数组被成功划分为三个区间,小于枢轴的元素在左侧,等于枢轴的元素在中间,大于枢轴的元素在右侧。
2.3 结合随机快排与荷兰国旗划分
在随机快排中引入荷兰国旗划分后,排序过程如下:
- 随机选择一个枢轴元素。
- 使用荷兰国旗划分算法将数组划分为三个区间:小于枢轴区间、等于枢轴区间和大于枢轴区间。
- 递归地对小于枢轴区间和大于枢轴区间进行随机快排。
- 由于等于枢轴区间的元素已经有序,无需再次排序,最终得到整个有序数组。
通过这种方式,随机快排 - 荷兰国旗划分不仅避免了传统快排的最坏情况,还能在一次划分中处理所有等于枢轴的元素,减少了递归调用的次数,进一步提高了排序效率。
三、代码实现
3.1 Python实现
import randomdef dutch_national_flag_partition(arr, pivot_index):pivot = arr[pivot_index]left, current, right = 0, 0, len(arr) - 1while current <= right:if arr[current] < pivot:arr[left], arr[current] = arr[current], arr[left]left += 1current += 1elif arr[current] == pivot:current += 1else:arr[current], arr[right] = arr[right], arr[current]right -= 1return left, rightdef randomized_quicksort(arr):if len(arr) <= 1:return arrpivot_index = random.randint(0, len(arr) - 1)left, right = dutch_national_flag_partition(arr, pivot_index)left_part = randomized_quicksort(arr[:left])right_part = randomized_quicksort(arr[right + 1:])equal_part = arr[left:right + 1]return left_part + equal_part + right_part# 测试
arr = [2, 0, 2, 1, 1, 0]
print(randomized_quicksort(arr))
3.2 Java实现
import java.util.Arrays;
import java.util.Random;public class RandomizedQuicksort {public static int[] dutchNationalFlagPartition(int[] arr, int pivotIndex) {int pivot = arr[pivotIndex];int left = 0, current = 0, right = arr.length - 1;while (current <= right) {if (arr[current] < pivot) {swap(arr, left, current);left++;current++;} else if (arr[current] == pivot) {current++;} else {swap(arr, current, right);right--;}}return new int[]{left, right};}public static void swap(int[] arr, int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}public static int[] randomizedQuicksort(int[] arr) {if (arr.length <= 1) {return arr;}Random random = new Random();int pivotIndex = random.nextInt(arr.length);int[] partitionIndices = dutchNationalFlagPartition(arr, pivotIndex);int left = partitionIndices[0];int right = partitionIndices[1];int[] leftPart = randomizedQuicksort(Arrays.copyOfRange(arr, 0, left));int[] rightPart = randomizedQuicksort(Arrays.copyOfRange(arr, right + 1, arr.length));int[] equalPart = Arrays.copyOfRange(arr, left, right + 1);int[] result = new int[leftPart.length + equalPart.length + rightPart.length];System.arraycopy(leftPart, 0, result, 0, leftPart.length);System.arraycopy(equalPart, 0, result, leftPart.length, equalPart.length);System.arraycopy(rightPart, 0, result, leftPart.length + equalPart.length, rightPart.length);return result;}public static void main(String[] args) {int[] arr = {2, 0, 2, 1, 1, 0};System.out.println(Arrays.toString(randomizedQuicksort(arr)));}
}
3.3 C++实现
#include <iostream>
#include <vector>
#include <ctime>
#include <cstdlib>
using namespace std;pair<int, int> dutch_national_flag_partition(vector<int>& arr, int pivot_index) {int pivot = arr[pivot_index];int left = 0, current = 0, right = arr.size() - 1;while (current <= right) {if (arr[current] < pivot) {swap(arr[left], arr[current]);left++;current++;}else if (arr[current] == pivot) {current++;}else {swap(arr[current], arr[right]);right--;}}return make_pair(left, right);
}vector<int> randomized_quicksort(vector<int> arr) {if (arr.size() <= 1) {return arr;}srand(time(nullptr));int pivot_index = rand() % arr.size();pair<int, int> partition_indices = dutch_national_flag_partition(arr, pivot_index);int left = partition_indices.first;int right = partition_indices.second;vector<int> left_part = randomized_quicksort(vector<int>(arr.begin(), arr.begin() + left));vector<int> right_part = randomized_quicksort(vector<int>(arr.begin() + right + 1, arr.end()));vector<int> equal_part(arr.begin() + left, arr.begin() + right + 1);vector<int> result;result.reserve(left_part.size() + equal_part.size() + right_part.size());result.insert(result.end(), left_part.begin(), left_part.end());result.insert(result.end(), equal_part.begin(), equal_part.end());result.insert(result.end(), right_part.begin(), right_part.end());return result;
}int main() {vector<int> arr = {2, 0, 2, 1, 1, 0};vector<int> sorted_arr = randomized_quicksort(arr);for (int num : sorted_arr) {cout << num << " ";}cout << endl;return 0;
}
四、性能分析
4.1 时间复杂度
随机快排 - 荷兰国旗划分在平均情况下的时间复杂度为 O ( n l o g n ) O(n log n) O(nlogn)。由于随机选择枢轴,使得每次划分都能大概率地将数组分成两个大致相等的子数组,递归深度为 O ( l o g n ) O(log n) O(logn),每次划分操作的时间复杂度为 O ( n ) O(n) O(n),因此整体时间复杂度为 O ( n l o g n ) O(n log n) O(nlogn)。在最坏情况下,虽然随机化枢轴选择降低了出现的概率,但仍有可能每次都选择到数组中的最大值或最小值,导致划分不均衡,此时时间复杂度退化为 O ( n 2 ) O(n^2) O(n2)。不过,这种极端情况发生的概率极小。
4.2 空间复杂度
随机快排 - 荷兰国旗划分的空间复杂度主要取决于递归调用栈的深度。在平均情况下,递归深度为 O ( l o g n ) O(log n) O(logn),因此空间复杂度为 O ( l o g n ) O(log n) O(logn);在最坏情况下,递归深度为 O ( n ) O(n) O(n),空间复杂度为 O ( n ) O(n) O(n)。此外,在划分过程中,虽然没有使用额外的与数组长度成正比的空间,但存在一些临时变量(如指针和交换过程中的临时存储),这些变量占用的空间为常数级,对整体空间复杂度影响较小。
五、实际应用场景
5.1 数据排序与预处理
在数据处理和分析领域,随机快排 - 荷兰国旗划分常用于对大规模数据进行排序。例如,在数据库查询结果的排序、日志文件中数据的整理等场景中,该算法能够高效地将数据按指定顺序排列,为后续的数据分析和处理提供基础。其随机化和优化的划分策略,使得在处理各种分布的数据时都能保持较好的性能。
5.2 并行计算与分布式系统
在并行计算和分布式系统中,随机快排 - 荷兰国旗划分可以用于数据的并行排序。将大规模数据划分为多个子数组,每个子数组在不同的计算节点上进行随机快排 - 荷兰国旗划分,最后合并结果。这种方式能够充分利用并行计算资源,提高排序效率,适用于处理海量数据的场景,如大数据分析平台中的数据排序任务。
That’s all, thanks for reading!
觉得有用就点个赞
、收进收藏
夹吧!关注
我,获取更多干货~
相关文章:

快速排序算法改进:随机快排-荷兰国旗划分详解
随机快速排序-荷兰国旗划分算法详解 一、基础知识回顾1.1 快速排序简介1.2 荷兰国旗问题 二、随机快排 - 荷兰国旗划分原理2.1 随机化枢轴选择2.2 荷兰国旗划分过程2.3 结合随机快排与荷兰国旗划分 三、代码实现3.1 Python实现3.2 Java实现3.3 C实现 四、性能分析4.1 时间复杂度…...

篇章二 论坛系统——系统设计
目录 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 1. 数据库设计 1.1 数据库名: forum db 1.2 表的设计 1.3 编写SQL 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 通过需求分析获得概念类并结合业务实现过程中的技术需要&#x…...
加密通信 + 行为分析:运营商行业安全防御体系重构
在数字经济蓬勃发展的时代,运营商作为信息通信网络的核心枢纽,承载着海量用户数据与关键业务传输,其安全防御体系的可靠性直接关乎国家安全、社会稳定与企业发展。随着网络攻击手段的不断升级,传统安全防护体系逐渐暴露出局限性&a…...
LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》
🧠 LangChain 中 TextSplitter 的使用详解:从基础到进阶(附代码) 一、前言 在处理大规模文本数据时,特别是在构建知识库或进行大模型训练与推理时,文本切分(Text Splitting) 是一个…...
Monorepo架构: Nx Cloud 扩展能力与缓存加速
借助 Nx Cloud 实现项目协同与加速构建 1 ) 缓存工作原理分析 在了解了本地缓存和远程缓存之后,我们来探究缓存是如何工作的。以计算文件的哈希串为例,若后续运行任务时文件哈希串未变,系统会直接使用对应的输出和制品文件。 2 …...
32单片机——基本定时器
STM32F103有众多的定时器,其中包括2个基本定时器(TIM6和TIM7)、4个通用定时器(TIM2~TIM5)、2个高级控制定时器(TIM1和TIM8),这些定时器彼此完全独立,不共享任何资源 1、定…...

热门Chrome扩展程序存在明文传输风险,用户隐私安全受威胁
赛门铁克威胁猎手团队最新报告披露,数款拥有数百万活跃用户的Chrome扩展程序正在通过未加密的HTTP连接静默泄露用户敏感数据,严重威胁用户隐私安全。 知名扩展程序存在明文传输风险 尽管宣称提供安全浏览、数据分析或便捷界面等功能,但SEMR…...

Matlab实现任意伪彩色图像可视化显示
Matlab实现任意伪彩色图像可视化显示 1、灰度原始图像2、RGB彩色原始图像 在科研研究中,如何展示好看的实验结果图像非常重要!!! 1、灰度原始图像 灰度图像每个像素点只有一个数值,代表该点的亮度(或…...
书籍“之“字形打印矩阵(8)0609
题目 给定一个矩阵matrix,按照"之"字形的方式打印这个矩阵,例如: 1 2 3 4 5 6 7 8 9 10 11 12 ”之“字形打印的结果为:1,…...
Vue3中的computer和watch
computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...

图解JavaScript原型:原型链及其分析 | JavaScript图解
忽略该图的细节(如内存地址值没有用二进制) 以下是对该图进一步的理解和总结 1. JS 对象概念的辨析 对象是什么:保存在堆中一块区域,同时在栈中有一块区域保存其在堆中的地址(也就是我们通常说的该变量指向谁&…...

《信号与系统》第 6 章 信号与系统的时域和频域特性
目录 6.0 引言 6.1 傅里叶变换的模和相位表示 6.2 线性时不变系统频率响应的模和相位表示 6.2.1 线性与非线性相位 6.2.2 群时延 6.2.3 对数模和相位图 6.3 理想频率选择性滤波器的时域特性 6.4 非理想滤波器的时域和频域特性讨论 6.5 一阶与二阶连续时间系统 6.5.1 …...
规则与人性的天平——由高考迟到事件引发的思考
当那位身着校服的考生在考场关闭1分钟后狂奔而至,他涨红的脸上写满绝望。铁门内秒针划过的弧度,成为改变人生的残酷抛物线。家长声嘶力竭的哀求与考务人员机械的"这是规定",构成当代中国教育最尖锐的隐喻。 一、刚性规则的必要性 …...

一些实用的chrome扩展0x01
简介 浏览器扩展程序有助于自动化任务、查找隐藏的漏洞、隐藏自身痕迹。以下列出了一些必备扩展程序,无论是测试应用程序、搜寻漏洞还是收集情报,它们都能提升工作流程。 FoxyProxy 代理管理工具,此扩展简化了使用代理(如 Burp…...

AxureRP-Pro-Beta-Setup_114413.exe (6.0.0.2887)
Name:3ddown Serial:FiCGEezgdGoYILo8U/2MFyCWj0jZoJc/sziRRj2/ENvtEq7w1RH97k5MWctqVHA 注册用户名:Axure 序列号:8t3Yk/zu4cX601/seX6wBZgYRVj/lkC2PICCdO4sFKCCLx8mcCnccoylVb40lP...
二维FDTD算法仿真
二维FDTD算法仿真,并带完全匹配层,输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...

02.运算符
目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&:逻辑与 ||:逻辑或 !:逻辑非 短路求值 位运算符 按位与&: 按位或 | 按位取反~ …...
Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解
文章目录 1. 题目描述1.1 链表节点定义 2. 理解题目2.1 问题可视化2.2 核心挑战 3. 解法一:HashSet 标记访问法3.1 算法思路3.2 Java代码实现3.3 详细执行过程演示3.4 执行结果示例3.5 复杂度分析3.6 优缺点分析 4. 解法二:Floyd 快慢指针法(…...
OCR MLLM Evaluation
为什么需要评测体系?——背景与矛盾 能干的事: 看清楚发票、身份证上的字(准确率>90%),速度飞快(眨眼间完成)。干不了的事: 碰到复杂表格(合并单元…...
React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构
React 实战项目:微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇!在前 29 篇文章中,我们从 React 的基础概念逐步深入到高级技巧,涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...

uni-app学习笔记三十五--扩展组件的安装和使用
由于内置组件不能满足日常开发需要,uniapp官方也提供了众多的扩展组件供我们使用。由于不是内置组件,需要安装才能使用。 一、安装扩展插件 安装方法: 1.访问uniapp官方文档组件部分:组件使用的入门教程 | uni-app官网 点击左侧…...

6.9-QT模拟计算器
源码: 头文件: widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMouseEvent>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);…...
[USACO23FEB] Bakery S
题目描述 Bessie 开了一家面包店! 在她的面包店里,Bessie 有一个烤箱,可以在 t C t_C tC 的时间内生产一块饼干或在 t M t_M tM 单位时间内生产一块松糕。 ( 1 ≤ t C , t M ≤ 10 9 ) (1 \le t_C,t_M \le 10^9) (1≤tC,tM≤109)。由于空间…...
【HarmonyOS 5】鸿蒙中Stage模型与FA模型详解
一、前言 在HarmonyOS 5的应用开发模型中,featureAbility是旧版FA模型(Feature Ability)的用法,Stage模型已采用全新的应用架构,推荐使用组件化的上下文获取方式,而非依赖featureAbility。 FA大概是API7之…...
土建施工员考试:建筑施工技术重点知识有哪些?
《管理实务》是土建施工员考试中侧重实操应用与管理能力的科目,核心考查施工组织、质量安全、进度成本等现场管理要点。以下是结合考试大纲与高频考点整理的重点内容,附学习方向和应试技巧: 一、施工组织与进度管理 核心目标: 规…...

java高级——高阶函数、如何定义一个函数式接口类似stream流的filter
java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用(Math::max) 2 函数接口…...
Java 与 MySQL 性能优化:MySQL 慢 SQL 诊断与分析方法详解
文章目录 一、开启慢查询日志,定位耗时SQL1.1 查看慢查询日志是否开启1.2 临时开启慢查询日志1.3 永久开启慢查询日志1.4 分析慢查询日志 二、使用EXPLAIN分析SQL执行计划2.1 EXPLAIN的基本使用2.2 EXPLAIN分析案例2.3 根据EXPLAIN结果优化SQL 三、使用SHOW PROFILE…...
Linux安全加固:从攻防视角构建系统免疫
Linux安全加固:从攻防视角构建系统免疫 构建坚不可摧的数字堡垒 引言:攻防对抗的新纪元 在日益复杂的网络威胁环境中,Linux系统安全已从被动防御转向主动免疫。2023年全球网络安全报告显示,高级持续性威胁(APT)攻击同比增长65%,平均入侵停留时间缩短至48小时。本章将从…...

数据结构第5章:树和二叉树完全指南(自整理详细图文笔记)
名人说:莫道桑榆晚,为霞尚满天。——刘禹锡(刘梦得,诗豪) 原创笔记:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 上一篇:《数据结构第4章 数组和广义表》…...

Windows电脑能装鸿蒙吗_Windows电脑体验鸿蒙电脑操作系统教程
鸿蒙电脑版操作系统来了,很多小伙伴想体验鸿蒙电脑版操作系统,可惜,鸿蒙系统并不支持你正在使用的传统的电脑来安装。不过可以通过可以使用华为官方提供的虚拟机,来体验大家心心念念的鸿蒙系统啦!注意:虚拟…...