Java算法OJ(7)随机快速排序

server/2024/12/18 17:53:38/

fb7f538c48644005a107eb6a3a760d38.jpeg


目录

1.前言

2.正文

1. 快速排序的基本原理

2. 随机快速排序的改进

3. 随机快速排序的步骤

3.小结


1.前言

哈喽大家好吖,今儿给大家带来算法—随机快速排序相关知识点,废话不多说让我们开始。

2.正文

在了解随机快排之前,先了解一下原始的快速排序是什么:

1. 快速排序的基本原理

快速排序是一种基于分治法的排序算法,主要步骤包括:

  1. 选取基准:从数组中选取一个基准元素,通常选择第一个元素、最后一个元素或中间元素。
  2. 分区:将数组分为两个子数组,使得左子数组的元素都小于基准,右子数组的元素都大于基准。
  3. 递归排序:分别对左、右子数组递归进行快速排序,直到子数组的长度为1。
java">public static void quickSort1(int[] arr, int l, int r) {if (l >= r) {return;}int x = arr[l + (int) (Math.random() * (r - l + 1))]; // 随机选择基准值int mid = partition1(arr, l, r, x); // 分区操作quickSort1(arr, l, mid - 1); // 递归排序左部分quickSort1(arr, mid + 1, r); // 递归排序右部分
}

 分区过程(partition1

  • 遍历 arr[l...r] 的所有元素,将小于等于 x 的元素放到左侧(<=x 区域),大于 x 的元素放到右侧。
  • 使用一个变量 a 来记录 <=x 区域的边界,并动态更新位置。
  • 遍历完成后,将等于 x 的最后一个元素放在 <=x 区域的最后位置,以确保分区后的基准值处于正确位置。
java">public static int partition1(int[] arr, int l, int r, int x) {int a = l, xi = 0; // a 记录 <=x 区域的边界,xi 用于记录 x 的位置for (int i = l; i <= r; i++) {if (arr[i] <= x) {swap(arr, a, i);if (arr[a] == x) {xi = a;}a++;}}swap(arr, xi, a - 1); // 将 x 放到 <=x 区域的末尾return a - 1; // 返回 x 的最终位置
}

2. 随机快速排序的改进

在传统的快速排序中,选择固定的基准可能导致较差的时间复杂度。比如,如果数组已经有序或逆序,选择第一个或最后一个元素作为基准会导致算法的性能退化到 O(n2)O(n^2)O(n2)。

改进版使用了“荷兰国旗问题”的分区方式,将数组分为小于基准值、等于基准值、大于基准值三部分,分别放在左中右,即不再是使用俩块的分区方式,而是在一个分区中将所有都等于基准值的数字都放到中间。这样在处理大量重复元素时效率更高。

3. 随机快速排序的步骤

java">public static void quickSort2(int[] arr, int l, int r) {if (l >= r) {return;}int x = arr[l + (int) (Math.random() * (r - l + 1))]; // 随机选择基准值partition2(arr, l, r, x); // 分区操作int left = first; // 左边界(小于 x 的部分的末尾)int right = last; // 右边界(等于 x 的部分的末尾)quickSort2(arr, l, left - 1); // 递归排序小于 x 的部分quickSort2(arr, right + 1, r); // 递归排序大于 x 的部分
}

分区过程(partition2

  • partition2 使用双指针方法实现了“荷兰国旗”分区。
  • 使用三个区域:<x(小于 x 的区域)、==x(等于 x 的区域)和 >x(大于 x 的区域)。
  • 通过遍历 arr[l...r],将小于 x 的元素放在左边,大于 x 的元素放在右边,等于 x 的元素放在中间。
  • 更新全局变量 firstlast,分别指向 ==x 区域的左右边界
java">public static int first, last;public static void partition2(int[] arr, int l, int r, int x) {first = l;last = r;int i = l;while (i <= last) {if (arr[i] == x) {i++;} else if (arr[i] < x) {swap(arr, first++, i++);} else {swap(arr, i, last--);}}
}

逻辑

  • 初始时 first 指向 llast 指向 ri 指针用于遍历数组。
  • arr[i] == x 时,i 向右移动,继续检查下一个元素。
  • arr[i] < x 时,表示当前元素属于 <x 区域,将其交换到 first 所指位置,并同时增大 firsti
  • arr[i] > x 时,表示当前元素属于 >x 区域,将其交换到 last 所指位置,并减少 last
  • 这样在遍历完成后,<x 区域、==x 区域和 >x 区域的边界已经划分完毕,firstlast 分别指向 ==x 区域的左边界和右边界。
java">public static void swap(int[] nums, int i, int j) {int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;}

这里再对比一下改进前和改进后的不同:

| 比较项       | quickSort1                                    | quickSort2                                                |
|--------------|----------------------------------------------|-----------------------------------------------------------|
| **效率**     | 适合普通数据集,但处理重复元素效率较低             | “荷兰国旗”分区方式更适合含有重复元素的数组,将等于基准值的部分集中在中间,减少重复元素的处理次数 |
| **递归调用** | 递归划分基于一个位置                             | 递归划分基于两个位置(`first` 和 `last`),有效减少递归深度 |
| **使用场景** | 适合一般数据集,重复元素较多时效率较低             | 推荐用于重复元素较多的数组,一般情况下也更高效                  |

下面这俩个是俩个排序的测试链接,一个是填函数风格,另一个是acm练习风格,本文仅将核心部分罗列出来,剩下的调试部分就交给大家了。

P1177 【模板】排序 - 洛谷 | 计算机科学教育新生态https://www.luogu.com.cn/problem/P1177912. 排序数组 - 力扣(LeetCode)https://leetcode.cn/problems/sort-an-array/description/

3.小结

今天的分享到这里就结束了,喜欢的小伙伴点点赞点点关注,你的支持就是对我最大的鼓励,大家加油!

 

 


http://www.ppmy.cn/server/151229.html

相关文章

<数据集>输电线塔杂物识别数据集<目标检测>

数据集下载链接 &#xff1c;数据集&#xff1e;输电线塔杂物识别数据集&#xff1c;目标检测&#xff1e;https://download.csdn.net/download/qq_53332949/90141102数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;1099张 标注数量(xml文件个数)&#xff1a;1099 …

CTFHub-ssrf

技能树--Web--SSRF 内网访问 开启题目 尝试访问位于127.0.0.1的flag.php吧 进入环境 根据提示输入即可 127.0.0.1/flag.php 伪协议读取文件 开启题目 尝试去读取一下Web目录下的flag.php吧 进入环境&#xff0c;根据提示输入 file:///var/www/html/flag.php 鼠标右键查看…

Hadoop学习

0 小结 一、Hadoop入门 1、常用端口号hadoop3.x HDFS NameNode 内部通常端口&#xff1a;8020/9000/9820HDFS NameNode 对用户的查询端口&#xff1a;9870Yarn查看任务运行情况的&#xff1a;8088历史服务器&#xff1a;19888hadoop2.x HDFS NameNode 内部通常端口&#xff1…

socket服务器多线程优化

在单线程环境下一个线程虽然可以执行任务但是所有的任务都交给一个线程来做当任务积累起来时&#xff0c;前面的任务会影响后续任务的执行&#xff0c;并且现在都是多核处理器我们需要尽可能利用cpu所以多线程 的优化就是一个不错的选择。 我们选择多线程后可以对任务进行分类…

IP数据云查询IP归属地信息

互联网时代&#xff0c;我们每天都会面对大量的网站或App,但你们是否知晓&#xff0c;所有程序员进行程序或者系统的开发都离不开查询IP地址&#xff0c;这是由于对于每个安全的网站/软件来说&#xff0c;基础的服务日志&#xff0c;登录IP等就离不开IP归属地离线库&#xff0c…

如何在服务器上安装 Maven

1. 安装Java Development Kit (JDK) 由于Maven依赖于Java运行环境&#xff0c;因此首先需要确保系统中已经安装了合适的JDK版本。 通过以下命令检查Java版本&#xff0c; java -version如果未安装JDK可以参考如何在服务器上安装 Java OpenJDK相关文档来安装特定版本的JDK。 …

UE5.1_常用路径函数及指向(未完成)

UE5常用路径函数及指向到底是掌握了吗?为什么每次使用每次得查找呢?怎么才能牢牢地记住? 记住源于实实在在掌握,先跟着看,或许可以看到与以往不同的点。 FPaths | Unreal Engine Documentationhttps://docs.unrealengine.com/5.1/en-US/API/Runtime/Core/Misc/FPaths/ …

Element plus 下拉框组件选中一个选项后显示的是 value 而不是 label

最近刚进行 Vue3 Element plus 项目实践&#xff0c;在进行表单二次封装的时候&#xff0c;表单元素 select 下拉框组件选中一个选项后显示的是 value 而不是 label&#xff0c;下面上代码&#xff1a; 原来的写法&#xff1a; <el-selectv-if"v.type select"…