java随机数排序算法_理解快速排序算法

快速排序在平均状况下,排序n个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n^2)次比较,但这种状况并不常见。事实上,快速排序通常明显比 其他Ο(n log n)算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。

快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists)。

步骤为:

1.从数列中挑出一个元素,称为”基准”(pivot), 2.重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition )操作。 3.递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

效果图如下:

AAffA0nNPuCLAAAAAElFTkSuQmCC

partition方法

partition方法是快速排序算法的核心,下面先写一个简单的原地(in-place)分区的版本。

[代码]java代码:01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27public class Test1   {

public static void main(String   args[]) {

int[]   a = {354,656,21,2342,65,657,76,12,54,778,50,31,333,45,56,86,97,121} ;

System.out.print(partition(a,2))   ;

}

static int partition(int arr[], int pivotIndex)

{

int start = 0 ;

int end = arr.length - 1 ;

int pivot = arr[pivotIndex];

swap(arr,pivotIndex,   end);

int storeIndex = start;

for(int i = start; i < end; ++i) {

if(arr[i]   < pivot) {

swap(arr,i,   storeIndex);

++storeIndex;

}

}

swap(arr,storeIndex,   end);

return storeIndex;

}

public  static    void    swap ( int [] data,  int  a,  int  b) {

int  t = data [a];

data   [a] = data [b];

data   [b] = t;

}

}

首先注意swap方法,swap方法用于交换数组中的两个元素。

partition当中调用了三次swap,我们随机选中一个位置作为”基准”(pivot),第一次交换就是把这个pivot交换到数组最后一位。 第三次当然就是把它从最后一位交换到它应该在的位置。中间的for循环是这个方法的核心。

storeIndex就是最后pivot摆放的位置。storeIndex前面的元素都比pivot小,storeIndex之后的元素都比pivot大。 所以我们从第一个元素遍历到最后一个,目的是把全部元素分成两段,storeIndex位于两段中间,第一段全部是是小于pivot的元素, 第二段都是大于pivot的元素,完成分段之后在把pivot从最后一个位置交换到两段中间。 循环时发现元素小于pivot,就把元素移动到后半段子序列的开头,然后把后半段开头的标记位storeIndex+1。这就是for循环里的工作。

要注意的是,一个元素在到达它的最后位置前,可能会被交换很多次。 下面对原地分区的版本进行优化如下:

[代码]java代码:01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19static int partition(int arr[], int pivotIndex)

{

int start = 0 ;

int end = arr.length -1;

int mid = arr[pivotIndex];

int left = start, right = end - 1;

while (left < right) {

while (arr[left] < mid && left <   right)

left++;

while (arr[right] >= mid && left   < right)

right--;

swap(arr,left,   right);

}

if (arr[left] >= arr[end])

swap(arr,left,   end);

else

left++;

return left;

}

现在我们采用了两个指针,对应两个子while循环,一个从前向后遍历,一个从后向前遍历。从前向后遍历时遇到大于基准数pivot的时候停止, 从后向前遍历时遇到小于基准数pivot的时候停止,然后交换两个数。

一旦我们有了这个分区算法,要写快速排列本身就很容易。

完整的快排算法

[代码]java代码:01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36public class Test2   {

static int[] arr  ;

private static void swap(int x, int y) {

int temp = arr[x];

arr[x]   = arr[y];

arr[y]   = temp;

}

private static void quick_sort_recursive(int start, int end) {

if (start >= end)

return;

int mid = arr[end];

int left = start, right = end - 1;

while (left < right) {

while (arr[left] < mid && left <   right)

left++;

while (arr[right] >= mid && left   < right)

right--;

swap(left,   right);

}

if (arr[left] >= arr[end])

swap(left,   end);

else

left++;

quick_sort_recursive(start,   left - 1);

quick_sort_recursive(left   + 1, end);

}

public static void sort(int[]   arrin) {

arr   = arrin;

quick_sort_recursive(0,   arr.length - 1);

}

public static void main(String   args[]) {

int[]   a =  {354,656,21,2342,65,657,76,12,54,778,50,31,333,45,56,86,97,121} ;

sort(a);

System.out.print(Arrays.toString(arr));

}

}

算法分析

快速排序的时间主要耗费在划分操作上,对长度为 k 的区间进行划分,共需 k-1 次关键字的比较。

最坏时间复杂度

最坏情况是每次划分选取的基准都是当前无序区中关键字最小(或最大)的记录,划分的结果是基准左边的子区间为空(或右边的子区间为空), 而划分所得的另一个非空的子区间中记录数目,仅仅比划分前的无序区中记录个数减少一个。 因此,快速排序必须做 n-1 次划分, 第i次划分开始时区间长度为 n-i+1,所需的比较次数为 n-i(1≤i≤n-1),故总的比较次数达到最大值:Cmax = n(n-1)/2=O(n^2)

如果按上面给出的划分算法,每次取当前无序区的第 1 个记录为基准,那么当文件的记录已按递增序(或递减序)排列时, 每次划分所取的基准就是当前无序区中关键字最小(或最大)的记录,则快速排序所需的比较次数反而最多。

最好时间复杂度

在最好情况下,每次划分所取的基准都是当前无序区的”中值”记录,划分的结果是基准的左、右两个无序子区间的长度大致相等。 总的关键字比较次数:O(nlgn)

注意: 用递归树来分析最好情况下的比较次数更简单。因为每次划分后左、右子区间长度大致相等,故递归树的高度为 O(lgn), 而递归树每一层上各结点所对应的划分过程中所需要的关键字比较次数总和不超过n,故整个排序过程所需要的关键字比较总次数 C(n)=O(nlgn)。

因为快速排序的记录移动次数不大于比较的次数,所以快速排序的最坏时间复杂度应为 O(n^2),最好时间复杂度为 O(nlgn)。

平均时间复杂度

尽管快速排序的最坏时间为 O(n^2),但就平均性能而言,它是基于关键字比较的内部排序算法中速度最快者,快速排序亦因此而得名。 它的平均时间复杂度为 O(nlgn)。

基准关键字的选取

在当前无序区中选取划分的基准关键字是决定算法性能的关键。

1.”三者取中”的规则

“三者取中”规则,即在当前区间里,将该区间首、尾和中间位置上的关键字比较,取三者之中值所对应的记录作为基准, 在划分开始前将该基准记录和该区伺的第1个记录进行交换,此后的划分过程与上面所给的 Partition 算法完全相同。

2.取位于 low 和 high 之间的随机数k(low≤k≤high),用 R[k] 作为基准

选取基准最好的方法是用一个随机函数产生一个取位于 low 和 high 之间的随机数 k(low≤k≤high),用 R[k] 作为基准, 这相当于强迫R[low..high]中的记录是随机分布的。用此方法所得到的快速排序一般称为随机的快速排序。

注意: 随机化的快速排序与一般的快速排序算法差别很小。但随机化后,算法的性能大大地提高了,尤其是对初始有序的文件, 一般不可能导致最坏情况的发生。算法的随机化不仅仅适用于快速排序,也适用于其它需要数据随机分布的算法。

空间复杂度

快速排序在系统内部需要一个栈来实现递归。若每次划分较为均匀,则其递归树的高度为 O(lgn),故递归后需栈空间为 O(lgn)。 最坏情况下,递归树的高度为 O(n),所需的栈空间为 O(n)。

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

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

相关文章

开课吧视频内容汇总

1. 前端读取文件内容&#xff0c; FileReader对象 2. 用户联网状态 3. application/x-www-form-urlencoded 参数序列化 &#xff08;具体借鉴jquery的$.param方法&#xff09;&#xff0c;后端接收到的数据格式是 a[0][a] 1,并不会将其整理成对象或者数组 var nextStr ;funct…

Servlet和JSP中的文件上传示例

使用Servlet和JSP将文件上传到服务器是Java Web应用程序中的常见任务。 在对Servlet或JSP进行编码以处理文件上传请求之前&#xff0c;您需要了解一点有关HTML和HTTP协议中文件上传支持的知识。 如果要让用户从文件系统中选择文件并上传到服务器&#xff0c;则需要使用<inpu…

20165312-第4周-课上内容补做以及知识点总结

20165312-第4周-课上内容补做以及知识点总结 1、课上内容补做 教材代码完成情况测试p45这题很快就做完了&#xff0c;然后忘记提交了。。就开始做递归。想起来的时候已经过了时间。 public class Example3_7 {public static void main(String args[]) {int sum0,i,j;for(i1;i&l…

JavaScript实现表单的全选,反选,获取值

构思 通过for循环和for in循环来实现&#xff0c;界面效果如下 步骤 全选&#xff1a; 循环给所有的表单设置checked 反选&#xff1a; 循环内判断checked是否为true&#xff0c;如果为true则改为false否则改为true 获取值&#xff1a; 最开始用for取&#xff0c;但是只打印最后…

EJB钝化和激活示例

在本教程中&#xff0c;我们将了解状态Java企业会话Bean中激活和钝化的工作方式。 1.简介 有状态会话Bean通常保存有关特定客户端的信息&#xff0c;并在整个会话中保存该信息。 但是&#xff0c;事实是&#xff0c;客户端会话往往会在相当长的时间内保持活动状态&#xff0c;…

命令模式详解

原文链接:https://www.cnblogs.com/java-my-life/archive/2012/06/01/2526972.html 在阎宏博士的《JAVA与模式》一书中开头是这样描述命令&#xff08;Command&#xff09;模式的&#xff1a; 命令模式属于对象的行为模式。命令模式又称为行动(Action)模式或交易(Transaction)模…

c mysql5.7_CentOS7下MySQL5.7的三种安装方式详解

操作系统环境&#xff1a;CentOS 7.4最小化安装[rootnode3 src]# cat /etc/redhat-releaseCentOS Linux release 7.4.1708 (Core)[rootnode3 ~]# uname -r3.10.0-693.5.2.el7.x86_64[rootnode3 ~]#安装版本为&#xff1a;MySQL 5.7.20一、编译安装MySQL5.71、下载源码包[rootno…

Struts2 学习之小白开始

Struts2 基础知识学习总结 Struts2 概述&#xff1a;Struts2 是一个用来开发 MVC 应用程序的框架&#xff0c;他提供了 Web 应用程序开发过程中的一些常见问题的解决方案&#xff0c;比如对于用户输入信息合法性的验证&#xff0c;统一的布局&#xff0c;国际化等&#xff0c;既…

机器学习的数学基础 - 信息论

机器学习的数学基础 - 信息论 信息论 信息论本来是通信中的概念&#xff0c;但是其核心思想“熵”在机器学习中也得到了广泛的应用。比如决策树模型ID3&#xff0c;C4.5中是利用信息增益来划分特征而生成一颗决策树的&#xff0c;而信息增益就是基于这里所说的熵。所以它的重要…

了解ElasticSearch分析器

令人遗憾的是&#xff0c;许多早期的互联网啤酒配方不一定采用易于消化的格式。 也就是说&#xff0c;这些食谱是通常在电子邮件或论坛帖子中最初组成的非结构化的方向和成分混合列表。 因此&#xff0c;尽管很难轻松地将这些配方放入传统的数据存储中&#xff08;表面上看是为…

c++简单程序设计-2

1.验证性实验部分①函数声明和函数定义各自的作用及二者的区别&#xff1a;函数声明就是调用函数之前提示一下有这个函数函数定义就是写一个函数②什么是形参&#xff1f;什么是实参&#xff1f;函数参数和返回值在函数中起到什么作用&#xff1f;函数定义时写的参数叫做形参&a…

Linux虚机安装配置Tomcat

d第一步&#xff1a;下载Tomcat包&#xff0c;网址http://tomcat.apache.org/ 选择tar.gz包下载&#xff0c;并传到虚机中 第二步&#xff1a;解压下载好的Tomcat包 命令&#xff1a;tar -zxvf apache-tomcat-8.0.53.tar.gz 第三步&#xff1a;配置环境变量 进入到Tomcat下bin包…

Nginx安装及配置详解

nginx概述 nginx是一款自由的、开源的、高性能的HTTP服务器和反向代理服务器&#xff1b;同时也是一个IMAP、POP3、SMTP代理服务器&#xff1b;nginx可以作为一个HTTP服务器进行网站的发布处理&#xff0c;另外nginx可以作为反向代理进行负载均衡的实现。 这里主要通过三个方面…

servlet简单概括总结

最近在看java web的相关内容&#xff0c;不管是整体还是细节&#xff0c;要学习的知识有很多&#xff0c;所以有一个好的学习体系非常重要。在阅读学习一些博客和教程中关于servlet的内容后&#xff0c;现将知识体系和自己的总结体会进行梳理&#xff0c;希望在更深入理解的同时…

php超强后门在任意位置创建文件,php大马:.user.ini文件构成的超强PHP后门

这个估计很多同学看了不屑&#xff0c;认为是烂大街的东西了&#xff1a;那么我来个新的吧&#xff1a;。它比用的更广&#xff0c;不管是nginx/apache/IIS&#xff0c;只要是以fastcgi运行的php都可以用这个方法。我的nginx服务器全部是fpm/fastcgi&#xff0c;我的IIS php5.3…

Restlet框架– Hello World示例

Restlet是用于Java平台的轻量级&#xff0c;全面的开源REST框架。 Restlet适用于服务器和客户端Web应用程序。 它支持主要的Internet传输&#xff0c;数据格式和服务描述标准&#xff0c;例如HTTP和HTTPS&#xff0c;SMTP&#xff0c;XML&#xff0c;JSON&#xff0c;Atom和WAD…

Servlet 3的异步Servlet功能

在深入了解什么是异步Servlet之前&#xff0c;让我们尝试了解为什么需要它。 假设我们有一个Servlet&#xff0c;处理时间很长&#xff0c;如下所示。 LongRunningServlet.java package com.journaldev.servlet;import java.io.IOException; import java.io.PrintWriter;impo…

excel的宏与VBA入门——代码调试

直接介绍重点&#xff1a; 常用的操作是导航栏的逐句与断点&#xff1a; 添加断点&#xff1a;调试->切换断点 单步运行&#xff1a;调试->逐句 查看变量的窗口&#xff1a;视图->本地窗口 转载于:https://www.cnblogs.com/jiangbei/p/9561352.html

php访问服务器文件路径,PHP与服务器文件系统的简单交互

1、php.ini中关于文件上传的设置指令2、文件上传过程(1)上传文件提交表单html代码&#xff1a;Adminstration - upoload new filesUpload new filesUpload a file(2)php处理上传文件代码①在php脚本中&#xff0c;需要处理的数据保存在超级变量数组$_FILES中&#xff0c;开启re…

django F和Q 关键字使用

F 的使用&#xff1a; 想给表里每个价格加上一百就要用上F&#xff0c;直接加是不行的。 转载于:https://www.cnblogs.com/wuheng-123/p/9561422.html