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

embedded/2024/11/22 5:26:54/

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/embedded/139530.html

相关文章

跨平台WPF框架Avalonia教程 八

构建跨平台应用程序 本指南介绍了Avalonia&#xff0c;并概述了如何构建跨平台应用程序&#xff0c;以最大程度地重用代码&#xff0c;并在所有主要平台&#xff08;Windows、Linux、macOS、iOS、Android和WebAssembly&#xff09;上提供高质量的用户界面体验。 与Xamarin.Fo…

【贪心算法】贪心算法四

贪心算法四 1.最长回文串2.增减字符串匹配3.分发饼干4.最优除法 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#x1f603; 1.最长回文串 题目链接&…

SpringMVC域对象共享数据

目录 一.向 request 域对象共享数据 1.1使用ServletAPI向request域对象共享数据 1.2使用ModelAndView向request域对象共享数据 1.3使用Model向request域对象共享数据 1.4使用map向request域对象共享数据 1.5使用ModelMap向request域对象共享数据 二.Model、ModelMap、Ma…

一文读懂Redis6的--bigkeys选项源码以及redis-bigkey-online项目介绍

一文读懂Redis6的--bigkeys选项源码以及redis-bigkey-online项目介绍 本文分为两个部分&#xff0c;第一是详细讲解Redis6的--bigkeys选项相关源码是怎样实现的&#xff0c;第二部分为自己对--bigkeys源码的优化项目redis-bigkey-online的介绍。redis-bigkey-online是自己开发的…

Springboot + vue 健身房管理系统项目部署

1、前言 ​ 许多人在拿到 Spring Boot 项目的源码后&#xff0c;不知道如何运行。我以 Spring Boot Vue 健身房管理系统的部署为例&#xff0c;详细介绍一下部署流程。大多数 Spring Boot 项目都可以通过这种方式部署&#xff0c;希望能帮助到大家。 ​ 2、项目查看 ​ 首…

Linux应用项目之量产工具(四)——UI系统

前言 前面我们完成了量产工具的显示、输入和文字系统&#xff0c;如下&#xff1a; 量产工具&#xff08;一&#xff09;——显示系统 量产工具&#xff08;二&#xff09;——输入系统 量产工具&#xff08;三&#xff09;——文字系统 项目框架 本节我们来实现量产工具的…

【大数据学习 | flume】flume Sink Processors与拦截器Interceptor

1. Failover Sink Processor 故障转移处理器可以同时指定多个sink输出&#xff0c;按照优先级高低进行数据的分发&#xff0c;并具有故障转移能力。 需要修改第一台服务器agent a1.sourcesr1 a1.sinksk1 k2 a1.channelsc1 a1.sources.r1.typenetcat a1.sources.r1.bindworker…

word转pdf保存高清图技巧

1. PPT编辑的图片转矢量图&#xff0c;导入word 2.PPT的图全选复制到visio&#xff0c;再从visio复制到word 3.使用adboe PDF word插件&#xff0c;另存为ADOBE PDF。 图片保存质量 另存为DPF< 导入PDF < 另存为ADOBE PDF 但是ADOBE PDF有时候图片保存出来会一片空白…