java jdk实现快速排序_Java实现快速排序过程分析

快速排序过程

没有既不浪费空间又可以快一点的排序算法呢?那就是“快速排序”!光听这个名字是不是就觉得很高端呢。

假设我们现在对“52 39 67 95 70 8 25

52'”这个8个数进行排序。首先在这个序列中随便找一个数作为基准数(不要被这个名词吓到了,就是一个用来参照的数,待会你就知道它用来做啥的了)。为了方便,就让第一个数70作为基准数吧。接下来,需要将这个序列中所有比基准数大的数放在70的右边,比基准数小的数放在70的左边,类似下面这种排列:

8 25 39 52 52' 67 70 95

在初始状态下,数字70在序列的第5位。我们的目标是将70挪到序列中间的某个位置,假设这个位置是k。现在就需要寻找这个k,并且以第k位为分界点,左边的数都小于等于70,右边的数都大于等于70。想一想,你有办法可以做到这点吗?

基本思想是分治的思想,说到分治,就应该想到和递归是分不开的。

有些书上会使用关键字比较的表述,有些书上会直接使用记录比较表述,这两种说法是两个维度上的说法。这里序列元素的关键字属于记录的一部分,为了简化问题,本文的讨论并不区分关键字和记录,代码实现中使用整数来表示记录。简而言之,本文的讨论简化为,对整型数组的快速排序。

通过一趟排序将要排序的记录分割成两部分,一部分的关键字值比别一部分的所有关键字都小,然后再依次对前后两部分的记录进行快速排序,递归该过程,直到序列中所有记录都是有序为止。

步骤

1)分解。选择第一个元素作为基准数,将输入序列array[m…n]划分成两个非空序列array[m…k]和array[k+1…n],使array[m…k]中任一元素的值不大于array[k+1…n]任一元素值。

2)递归求解。通过递归调用快排算法分别对array[m…k]和array[k+1…n]进行排序

3)合并。由于对分解出的两个子序列排序都是原地进行的,所以在array[m…k]和array[k+1…n]都排好序后不需要再执行任何计算,就能将array[m…n]排好序。因此这一步是不需要在程序中体现的。

排序过程分析

初始关键字:52 39 67 95 70 8 25 52' ,下面将列出每一趟执行的结果。

基准52: 52 39 67 95 70 8 25 52'

基准25: 8 25 39 52 70 95 67 52‘

基准70: 8 25 39 52 52' 67 70 95

基准52‘:8 25 39 52 52' 67 70 95

算法分析

快速排序的时间复杂度与关键字初始序列有关。

最坏时间复杂度:O(n^2):

以第一个数或最后一个数为基准时,当初始序列整体或局部有序时,快速排序的性能会下降。若整体有序,此时,每次划分只能分出一个元素,具有最坏时间复杂度,快速排序将退化成冒泡排序。

最好时间复杂度:

每次选取的基准关键字都是待排序列的中间值,也就是说每次划分可以将序列划分为长度相等的两个序列。快速排序的递归过程可以用一棵二叉树来表示,递归树的高度是2为底的对数,每层需要比较的次数是n/2,所以最好时间复杂度是O(n*以2为底n的对数),因为很多时候输入序列都是乱序的,所以最好时间复杂度也是平均时间复杂度。

三种快排和四种优化方法

三种快排

这里区分的方式是不同基准的选择方法:

1)固定位置,取第一个或最后一个元素作为基准。这种选取方法不合适局部有序的输入。

2)随机选取基准,利用随机算法,选取待排序序列中任意一个元素作为基准。

3)三数取中,取数列中第一个数,中间位置的数,最后一个数作一个平均值作为基准。

四种优化

1)当排序序列长度分割到一定程度时,使用插入排序

对于N很小或局部有序的数组,直接插入排序的效率非常高。

2)在一次分割结束后,可以把与基准数相等的元素聚在一起,下次分割时忽略掉这些元素。

对于含有重复元素比较多的序列,这种优化方法效果比较好,可以减少很多跌代次数。

具本过程:

第一步:在划分过程,把与所选取的基准数相等的元素放在数组的两端。

第二步:划分结束后,把两端的与基准数相等的元素移到基准数最终位置的两侧。

3)优化递归操作。

4)使用多线程并行处理子划分。

Partition方法在求TopK问题上的应用

TopK问题即求序列中最大或最小的K个数。这里以求最小K个数为例。

快速排序的思想是使用一个基准元素将数组划分成两部分,左侧都比基准数小,右侧都比基准数大。

给定数组array[low…high],一趟快排划分后的结果有三种:

1)如果基准数左侧元素个数Q刚好是K-1,那么在基准数左侧(包含基准数本身),即为TopK的所有元素。

2)如果基准数左侧元素个数Q小于K-1,那么说明基准数左侧的Q个数都是TopK里的元素,只需要在基准数的右侧找出剩下的K-Q个元素即可。问题转化成了以基准数下标为起点,高位(high)为终点的Top(K-Q)。递归下去即可。

3)如果基准数左侧元素个数Q大于K-1,说明第K个位置,在基准数的左侧,需要缩小搜索范围,在低位(low)至基准数位置重复递归即可,最终问题会转化成上面两种情况。

快排java实现

在手写快排算法时,最好先把一趟排序的过程写出来。

package sort;

public class QuickSort {

// 暴露只一个参数的公共接口

public void quickSort(int a[]) {

sort(a, 0, a.length - 1);

}

// 快排算法的真正实现

private void sort(int[] a, int low, int high) {

if (low >= high)

return;

int i = low, j = high; // 设置这两个变量的目的是为了保持low和high不变

int pivotNum = a[i]; // 基准数

while (i < j) {

while (a[j] >= pivotNum && j > i) { // 循环结束的条件有二:一是找到比支点小的数,二是j==i

j--;

}

if (j > i) { // 由于上面循环结束的功能性有两个,对于找到比支点小的数,即j!=i,要进行位置的交换,下同

a[i] = a[j];

i++;

}

while (a[i] < pivotNum && i < j) {

i++;

}

if (i < j) {

a[j] = a[i];

j--;

}

}

a[i] = pivotNum;

sort(a, low, i - 1);

sort(a, i + 1, high);

}

public static void main(String[] args) {

int[] a = { 52, 39, 67, 95, 70, 8, 25, 52 };

new QuickSort().quickSort(a);

for (int i : a) {

System.out.print(i + " ");

}

}

}

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

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

相关文章

深入理解计算机系统读书笔记

由于这本书的前半部分习题大多是相关计算和简单汇编代码编写&#xff0c;所以当时都是在稿纸上练习的&#xff0c;不过现在那些稿纸似乎也不见了: ( 所以现在仅有后半部分的课后习题代码以及示例练习代码&#xff08;家里作业习题当时并没有做&#xff0c;准备阅读第二遍时再做…

Blazor University (6)组件 — 组件事件

原文链接&#xff1a;https://blazor-university.com/components/component-events/组件事件源代码[1]EventCallback<T> 类是一个特殊的 Blazor 类&#xff0c;可以作为参数公开&#xff0c;以便组件可以在发生感兴趣的事情时轻松通知使用者。一旦声明了 EventCallback&l…

JavaScript匿名函数以及在循环中的匿名函数

一 历史 JavaScript其实是一门奇异的语言&#xff0c;TA的一大特性是没有块级作用域 for(var i0;i<10;i){} console.log(i)大家猜测下值是多少&#xff1f;答案是 10&#xff0c; 虽然我们在一个块内申明了变量&#xff0c;但i却是在全范围内起作用的&#xff0c;所以就引入…

Linux内核笔记--内存管理之用户态进程内存分配

内核版本&#xff1a;linux-2.6.11 Linux在加载一个可执行程序的时候做了种种复杂的工作&#xff0c;内存分配是其中非常重要的一环&#xff0c;作为一个linux程序员必然会想要知道这个过程到底是怎么样的&#xff0c;内核源码会告诉你这一切。 线性区 一个可执行程序&#xff…

Android之javax.net.ssl.SSLPeerUnverifiedException: Hostname ip not verified:解决办法

1、问题 用HttpURLConnection去请求的时候抛了下面的异常 HttpRequest$HttpRequestException: javax.net.ssl.SSLPeerUnverifiedException: Hostname ip not verified: 2、分析和解决 从异常来看是因为SSL协议握手的过程中,这个服务度地址的证书没有被证实,被信任。 clien…

php 字符串进行计算_怎么在php中利用eval对字符串格式进行计算

怎么在php中利用eval对字符串格式进行计算发布时间&#xff1a;2020-12-16 16:42:57来源&#xff1a;亿速云阅读&#xff1a;101作者&#xff1a;Leah本篇文章给大家分享的是有关怎么在php中利用eval对字符串格式进行计算&#xff0c;小编觉得挺实用的&#xff0c;因此分享给大…

Xamarin效果第十四篇之玩耍GIS

最近再次拾起Xamarin然后也实现了祖传PLC控制和弹窗配置;这不又一次勾起来我想基于他玩玩原来一直玩耍的GIS,毕竟咱前面一直玩耍二维和三维的GIS相关的知识点;有兴趣的小伙伴可以翻翻我的历史文章;趁着激情满满;来看看最终咱实现的加载高德平面地图效果(有水印):再者就是满足群…

Android下载apk异常java.net.SocketTimeoutException: timeout解决办法

1、问题 实现下载apk的时候&#xff0c;抛出下面异常 java.net.SocketTimeoutException: timeout 2、分析 很明显是socket超时了&#xff0c;由于我的wifi网络比较慢&#xff0c;设置的超时时间可能短了。 在写入由 GetRequestStream 方法返回的流时&#xff0c;或在读取由…

SQL SERVER两种分页的存储过程介绍

由于现在很多的企业招聘的笔试都会让来招聘的写一个分页的存储过程,有的企业甚至要求应聘者用两种方式实现分页,如果没有在实际项目中使用过分页,那么很多的应聘者都会出现一定的问题,下面介绍两种分页的方法。 一、 以学生表为例,在数据库中有一个Student表,字段有 …

Java Socke 探究

Java中的Socket可以分为普通Socket和NioSocket两种。 普通Socket的用法 Java中的网络通信是通过Socket实现的&#xff0c;Socket分为ServerSocket和Socket两大类&#xff0c;ServerSocket用于服务端&#xff0c;可以通过accept方法监听请求&#xff0c;监听到请求后返回Socket&…

codeforces 600D Area of Two Circles' Intersection

分相离&#xff0c;内含&#xff0c;想交三种情况讨论一下。 主要是精度和数据范围的问题&#xff0c;首先数据用long double&#xff0c;能用整型判断就不要用浮点型。 题目中所给的坐标&#xff0c;半径是整型的&#xff0c;出现卡浮点判断的情况还是比较少的。 最后算三角型…

PHP进程退出信号_一文吃透 PHP 进程信号处理

背景前两周老大给安排了一个任务&#xff0c;写一个监听信号的包。因为我司的项目是运行在容器里边的&#xff0c;每次上线&#xff0c;需要重新打包镜像&#xff0c;然后启动。在重新打包之前&#xff0c;Dokcer会先给容器发送一个信号&#xff0c;然后等待一段超时时间(默认1…

GitHub Copilot 现已登陆 Visual Studio!

激动人心的好消息来了&#xff0c;GitHub 在3月29日发布博客&#xff0c;宣布 Github Copilot 现在可以在 Visual Studio 中使用。我们知道 Visual Studio 的 IntelliCode 本身已经很智能了, 现在又迎来了 Copilot, 编程体验将进入新的篇章。如何安装? 首先&#xff0c;您…

经典实用SQL语句大全汇总

目 录 1.随机取3条记录 2.随机选记录 3.删除重复记录 4.创建数据库 5.列出表里的所有的列名 6.选择从10到15的记录 7.压缩数据库

java之写接口回调编程经验改进

1、问题 在一个类里面数据的变化需要在另外一个类里面动态得到&#xff0c;比如在我的异步任务里面下载的数据&#xff0c;需要在UI界面的ProgressDialog里面动态显示&#xff0c;我们需要在异步任务里面写个接口&#xff0c;然后接口里面有一些函数&#xff0c;至于在Progres…

Mac Ubuntu ----端口被占用

Mac下使用lsof&#xff08;list open files&#xff09;来查看端口占用情况&#xff0c;lsof 是一个列出当前系统打开文件的工具。 使用 lsof 会列举所有占用的端口列表&#xff1a; 1$ lsof使用less可以用于分页展示&#xff0c;如&#xff1a; 1$ lsof | less也可以使用 -i 查…

iOS 9音频应用播放音频之音量设置与声道设置

iOS 9音频应用播放音频之音量设置与声道设置 iOS 9音频应用音量设置 音量又称响度、音强&#xff0c;是指人耳对所听到的声音大小强弱的主观感受&#xff0c;其客观评价尺度是声音的振幅大小。在iOS 9音频应用的应用中&#xff0c;经常会出现播放的音乐音量过大或者过小。此时i…

nginx配置文件中的location中文详解

location 语法:location [|~|~*|^~] /uri/ { … }默认:否 上下文:server 这个指令随URL不同而接受不同的结构。你可以配置使用常规字符串和正则表达式。如果使用正则表达式&#xff0c;你必须使用 ~* 前缀选择不区分大小写的匹配或者 ~ 选择区分大小写的匹配。 确定 哪个locati…

php fpm工作原理,什么是phpfpm的工作原理?

什么是phpfpm的工作原理&#xff1f;发布时间&#xff1a;2020-07-13 15:12:53来源&#xff1a;亿速云阅读&#xff1a;181作者&#xff1a;Leah什么是phpfpm的工作原理&#xff1f;针对这个问题&#xff0c;这篇文章详细介绍了相对应的分析和解答&#xff0c;希望可以帮助更多…

C#对象映射器之Mapster

简介Mapster是一个快&#xff0c;小巧&#xff0c;功能强大的对象映射.Net框架例子我有两个Model类且他们的属性一致&#xff0c;我们将 SourceObjectTest赋值给DestObjectTest该怎么做&#xff1f;SourceObjectTest sourceObject new SourceObjectTest(); sourceObject.Name …