Java实现快速排序

1.介绍

       快排分为两种:

       1.lomuto分区算法  (快慢指针)(单边)

       2.Hoare分区算法   (前后指针)(双边)

快排主要思想:选一个基准元素分为两部分,先让左边排一下序再让右边排序 

2.思路分析

1.lomuto分区算法 

默认:最右边的元素作为基准点

1.设置两个指针(dest , cur),通过使用dest找比基准点大的,cur找比基准点小的

2.当同时停下并且不相等进行交换,这样会达到一种dest是比基准点小的分界点,左边全是比基准点小的,走到最后一步只需要与基准点交换即可。遍历序列并交换元素:从序列的第一个元素开始,逐个与基准元素进行比较,将小于等于基准元素的元素交换到序列的左侧。

3.更新基准元素位置:遍历完成后,将基准元素交换到正确的位置上,使得基准元素左侧的元素都小于等于它,右侧的元素都大于它。

4.分治递归:对基准元素左右两侧的子序列分别重复以上步骤,直到每个子序列只剩下一个元素或为空。

平均复杂度:O(nlogn)

最坏情况:O(n^2)

2.分析普通快排存在的缺点

        1.在最坏情况下,即每次划分都导致一个子序列为空

        我们可以通过随机基准点进行优化,以防止出现这种情况

        2.数据量很少的时候,快排并不有优势,反倒不如插入排序,所以我对其进行了当元素小于10时候,我就使用插入排序。

3.Hoare分区算法

 默认: 最左边的元素为基准点

注意点:一定要先移动右指针,在移动左指针,因为右指针找是比基准点小的,谁先走就意味着最后一轮谁过后谁先移动去找另一个,而右指针最后一次交换存的是比基准点大的,左指针是比基准点小的,要是先移动左指针就会使一个比基准点大的元素放在基准点前面     

3.代码实现

1.lomuto分区算法 


/**实现快速排序(单边循环)** lomuto快速排序* */public class sortTest9 {private int[] data;public void sort(int[] data){this.data = data;dfs(0,data.length - 1);}private void dfs(int start, int end) {//分区的时候只有一个元素结束递归if (start == end) return;//分区(已基准点分区)int j = partition(start,end);//左分区dfs(j - 1, end);//右分区dfs(start, j + 1);}private int partition(int start, int end) {//定义基准数int prev = data[end];int less = start;//慢指针int great = start;//快指针for (; great < end - 1; great++) {if (data[great] < prev){//防止无意义的空交换if (great != less) swap(data,less,great);less++;}}//到最后交换基准数(也就是end的值)和慢指针less的值swap(data,less,end);//慢指针所在的位置就是分区的位置return less;}private void swap(int[] data, int less, int great) {int temp = data[less];data[less] = data[great];data[great] = temp;}
}

2.Hoare分区算法


/**实现快速排序(双边循环)** */public class sortTest10 {private int[] data;public void sort(int[] data){this.data = data;dfs(0,data.length - 1);}private void dfs(int start, int end) {int i = start;int j = end;//定义基准数int prev = data[start];if (i > j){return;}//处理重复元素(相等的也交换)并且双指针都移动while(i != j){//后指针找比基准数小的while(true) {//等于不等于都一样(基准数左边可以含有等于基准点的数右边也可以)if (i < j && data[j] < prev) {break;}j--;}//前指针找比基准数大的while(true){if (i < j && data[i] > prev) break;i++;}swap(i,j);j--;i++;}//确定了两指针指向头一个与基准数交换swap(j,start);//左分区swap(start,j - 1);//右分区swap(j + 1,end);}//用来交换元素private void swap(int less, int great) {int temp = data[less];data[less] = data[great];data[great] = temp;}
}

3.缺点优化

        1.随机基准点

        2.处理重复元素

        3.当递归到元素小于10的时候转为插入排序

import java.util.Arrays;
import java.util.Random;public class sortTest11 {private static final int INSERTION_SORT_THRESHOLD = 10;public static void quickSort(int[] array) {quickSort(array, 0, array.length - 1);}private static void quickSort(int[] array, int start, int end) {if (start < end) {// 当元素个数小于等于阈值时,使用插入排序if (end - start + 1 <= INSERTION_SORT_THRESHOLD) {insertionSort(array, start, end);} else {// 随机选择基准值,并进行划分int pivotIndex = randomPartition(array, start, end);// 对基准值左侧的子数组递归排序quickSort(array, start, pivotIndex - 1);// 对基准值右侧的子数组递归排序quickSort(array, pivotIndex + 1, end);}}}private static int randomPartition(int[] array, int start, int end) {int randomIndex = new Random().nextInt(end - start) + start;swap(array, randomIndex, start);return partition(array, start, end);}private static int partition(int[] array, int start, int end) {int pivot = array[start];int left = start + 1;int right = end;while (left <= right) {while (left <= right && array[left] <= pivot) {left++;}while (left <= right && array[right] > pivot) {right--;}if (left < right) {swap(array, left, right);left++;right--;}}swap(array, start, right);return right;}private static void insertionSort(int[] array, int start, int end) {for (int i = start + 1; i <= end; i++) {int key = array[i];int j = i - 1;while (j >= start && array[j] > key) {array[j + 1] = array[j];j--;}array[j + 1] = key;}}private static void swap(int[] array, int i, int j) {int temp = array[i];array[i] = array[j];array[j] = temp;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/105874.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Java】工具类的设计

工具类设计思想 构造方法用 private 修饰 外部无法new成员方法使用 public static 修饰 通过类名称 . 方法名称 访问 示例代码&#xff1a; Test11_1.java&#xff1a;设计一个工具类 package com.api.Demo07;import java.util.Arrays;public class Test11_1 {/*** 将数组中 …

简单好用的解压缩软件:keka 中文 for mac

Keka是一款功能全面、易于使用的文件压缩和解压缩软件&#xff0c;为Mac用户提供了便捷的文件管理工具。它支持多种压缩格式&#xff0c;具有快速解压和强大的压缩功能&#xff0c;让您能够轻松地处理各种文件压缩需求。 隐私非常重要 安全共享只需设置密码并创建高度加密的文…

深度强化学习 第 2 章 蒙特卡洛

2.1随机变量 强化学习中会经常用到两个概念&#xff1a; 随机变量、 观测值。 本书用大写字母表示随机变量&#xff0c;小写字母表示观测值&#xff0c;避免造成混淆。 下面我们定义概率质量函数&#xff08;probability mass function&#xff0c;缩写 PMF&#xff09;和概率…

mkdir-创建目录文件

mkdir命令来自英文词组”make directories“的缩写,其功能是用来创建目录文件。使用方法简单,但需要注意若要创建的目标目录已经存在,则会提示已存在而不继续创建,不覆盖已有文件。 语法格式:mkdir [参数] 目录名 参数说明-m创建目录的同时设置权限-p递归创建多级目录-v显…

课程表系列

相关题目&#xff1a; 207. 课程表 210. 课程表 II 1462. 课程表 IV class CourseSchedule:"""207.课程表https://leetcode.cn/problems/course-schedule/"""def __init__(self):# 记录⼀次递归堆栈中的节点self.onPath []# 记录遍历过的节点&…

LINUX定时解压缩方案

需求背景 对接客户中某个上游为外包系统&#xff0c;外包系统每日推送压缩文件至指定文件夹下&#xff0c;文件格式为YYYYMMDD_RegReport.zip。由于每日采集文件&#xff0c;无法对接压缩包内文件&#xff0c;需要将推送的压缩文件每日解压为文件夹 需求分析 与客户沟通后&a…

Kafka知识补充

如何避免 Rebalance 最简单粗暴的就是 &#xff1a; 减少组成员数量发生变化 每个 Consumer 实例都会定期地向 Coordinator 发送心跳请求&#xff0c;表明它还存活着。如果某个 Consumer 实例不能及时地发送这些心跳请求&#xff0c;Coordinator 就会认为该 Consumer 已经“死…

HarmonyOS 远端状态订阅开发实例

IPC/RPC 提供对远端 Stub 对象状态的订阅机制&#xff0c; 在远端 Stub 对象消亡时&#xff0c;可触发消亡通知告诉本地 Proxy 对象。这种状态通知订阅需要调用特定接口完成&#xff0c;当不再需要订阅时也需要调用特定接口取消。使用这种订阅机制的用户&#xff0c;需要实现消…

Tensorflow2 中对模型进行编译,不同loss函数的选择下输入数据格式需求变化

一、tf2中常用的损失函数介绍 在 TensorFlow 2 中&#xff0c;编译模型时可以选择不同的损失函数来定义模型的目标函数。不同的损失函数适用于不同的问题类型和模型架构。下面是几种常见的损失函数以及它们的作用和适用场景&#xff1a; 1.均方误差&#xff08;Mean Squared …

C++初阶(1)

W...Y的主页&#x1f60a; 代码仓库分享&#x1f495; ​ &#x1f354;前言&#xff1a; 今天我们正式进入C篇章&#xff0c;作为学过C语言的同志&#xff0c;继续学习C肯定就不会进行那些与C语言相同的学习&#xff0c;因为C语言的内容在C中也可以正常使用&#xff0c;所…

通过示例详细了解ES6导入导出模块

通过示例详细了解ES6导入导出模块 似乎许多开发人员认为 ES6 模块只不过是export、import关键字。事实上&#xff0c;它更加多样化。它拥有强大的功能和鲜为人知的问题。在本文中&#xff0c;我们将使用一些示例来了解这些内容。 示例一 // index.mjs import { default } fr…

标准误与聚类稳健标准误的理解

1 标准误 1.1 定义 标准误&#xff08;Standard Error&#xff09;是用来衡量统计样本估计量&#xff08;如均值、回归系数等&#xff09;与总体参数之间的差异的一种统计量。标准误衡量了样本估计量的变异程度&#xff0c;提供了对总体参数的估计的不确定性的度量。标准误越…

动网格模型算法基础(二)

本贴主要简述动网格模型算法 FLUENT动网格模型能够根据用户指定的边界运动、网络类型和网格再生方式自动地调节内部体网格节点的位置。 一、动网格使用面临的量大问题&#xff1a; 体网格的再生&#xff1b;边界运动或变形的指定&#xff1b; 二、体网格再生方法&#xff1…

flask vue跨域问题

问题&#xff1a; 调试时候跨域访问报&#xff1a; Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response. 解决办法&#xff1a; 安装flask_cros from flask_cors import CORS CORS(app) app.after_request def a…

如何避免大语言模型绕过知识库乱答的情况?LlamaIndex 原理与应用简介

本文首发于博客 LLM 应用开发实践 随着 LangChain LLM 方案快速普及&#xff0c;知识问答类应用的开发变得容易&#xff0c;但是面对回答准确度要求较高的场景&#xff0c;则暴露出一些局限性&#xff0c;比如向量查询方式得到的内容不匹配&#xff0c;LLM 对意图识别不准。所…

C++类型推导

这里对C的类型推导方式进行一次全面的总结。 C中有三种类型推导的方式&#xff0c;分别是模板、auto以及decltype()。以下分别介绍这三种方式的同异。 一 模板 假设有这样的函数模板和这样的调用&#xff1a; template<typename T> void f(ParamType param);f(expr);…

【Linux】多线程

文章目录 一.Linux线程概念1.什么是线程2.二级页表3.线程的优点4.线程的缺点5.线程异常6.线程用途 二.Linux进程VS线程1.进程和线程2.进程的多个线程共享3.进程和线程的关系 三.Linux线程控制1.POSIX线程库2.线程创建3.线程等待4.线程终止5.分离线程6.线程ID及进程地址空间布局…

手机拍摄的视频噪点很多怎么办,视频怎么做降噪处理?

现如今&#xff0c;智能手机已经成为了我们生活中必不可少的存在。而随着智能手机越来越强大&#xff0c;很多人已经开始使用手机来拍摄各种类型的视频。但是由于手机的限制&#xff0c;很多人会发现自己拍摄的视频存在着很多的噪点。那么&#xff0c;我们该怎样来解决拍摄视频…

N点复序列求2个N点实序列的快速傅里叶变换

一、方法简介 通过一个点复数序列求出两个点实数序列的离散傅里叶变换&#xff0c;进一步提升快速傅里叶变换的效率。 二、方法详解 和是实数序列&#xff0c;且长度都为&#xff0c;定义复数序列&#xff1a; &#xff0c; 则序列和可表示为&#xff1a; 的离散傅…

端到端的机器学习项目(Machine Learning 研习之六)

使用真实数据 当你在研习机器学习时&#xff0c;最好是使用真实世界中的数据&#xff0c;而不是采用人工数据。巧的是&#xff0c;数以千计的数据集可供选择&#xff0c;涵盖了各种领域。 流行的开放数据存储库&#xff1a; OpenML.orgKaggle.compaperswithcode.com UC Irvin…