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

news/2024/11/18 13:30:08/

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/news/1547993.html

相关文章

【网络安全】XSS注入

一、什么是XSS注入 XSS&#xff08;Cross-Site Scripting&#xff09;注入是一种网络安全漏洞&#xff0c;它允许攻击者向网站注入恶意脚本代码&#xff0c;然后在用户的浏览器上执行。 二、XSS注入有哪些危害 盗取用户的敏感信息&#xff1a;攻击者可以通过注入恶意脚本代码…

Docker在微服务架构中的最佳实践

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 Docker在微服务架构中的最佳实践 Docker在微服务架构中的最佳实践 Docker在微服务架构中的最佳实践 引言 Docker 概述 定义与原理…

2411rust,异步函数

原文 Rust异步工作组很高兴地宣布,在实现在特征中使用异步 fn的目标方面取得了重大进度.将在下周发布稳定的Rust1.75版,会包括特征中支持impl Trait注解和async fn. 稳定化 自从RFC#1522在Rust1.26中稳定下来以来,Rust就允许用户按函数的返回类型(一般叫"RPIT")编…

第74期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…

认识c++(c++入门)

1. C关键字 C关键字是语言本身的一部分&#xff0c;它们有特定的含义&#xff0c;并被用作程序的基础结构。以下是C标准中定义的关键字列表&#xff1a; 2. 命名空间 在C中&#xff0c;命名空间&#xff08;Namespace&#xff09;是一种用来组织代码的方法&#xff0c;它可以…

Ue5 umg学习(二)图像控件,锚点

视频资料4、图像控件_哔哩哔哩_bilibili 选择通用下的图像 将其拉入画布中&#xff0c;会拉出一个小白块的东西 点击小白块&#xff0c;会发现右侧的属性。 左上角像花一样的是锚点。 首先选择图片 这里需要一张ui图片&#xff0c;我截图了一张图片作为例子&#xff0c;其他图…

服务器虚拟化技术详解及应用案例

服务器虚拟化技术详解及应用案例 在现代数据中心和云计算环境中,服务器虚拟化技术已经成为提高资源利用率、降低成本和简化管理的重要手段。本文将详细介绍服务器虚拟化的基本概念、主要类型、技术特性、应用优势,并通过一个基于Golang的容器化Web服务器管理案例展示虚拟化技…

Vue3+TypeScript对于SVG的使用

效果图如下 代码解释 <svg click"handleSvgClick" mousemove"handleMouseMove" :width"svgWidth" :height"svgHeight" style"position: absolute; top: 0; lef…