Java快速排序案例讲解

交换类排序主要是通过两两比较待排元素的关键字,若发现与排序要求相逆,则“交换”之。在这类排序方法中最常见的是冒泡排序和快速排序。上一篇简单写了冒泡排序,这次简单写一写快速排序。

快速排序的思想:

快速排序是将分治法运用到排序问题中的一个典型例子,其基本思想是:通过一个枢轴(pivot)元素将 n 个元素的序列分为左、右两个子序列 Ll 和 Lr,其中子序列 Ll中的元素均比枢轴元素小,而子序列 Lr 中的元素均比枢轴元素大,然后对左、右子序列分别进行快速排序,在将左、右子序列排好序后,则整个序列有序,而对左右子序列的排序过程直到子序列中只包含一个元素时结束,此时左、右子序列由于只包含一个元素则自然有序。

对待排序序列进行划分:

使用两个指针 low 和 high 分别指向待划分序列 r 的范围,取 low 所指元素为枢轴,即 pivot = r[low]。划分首先从 high 所指位置的元素起向前逐一搜索到第一个比 pivot 小的元素,并将其设置到 low 所指的位置;然后从 low 所指位置的元素起向后逐一搜索到第一个比 pivot 大的元素,并将其设置到 high 所指的位置;不断重复上述两步直到 low = high 为止,最后将 pivot 设置到 low 与 high 共同指向的位置。

图示划分:

代码实现:

import java.util.Arrays;

public class QuickSortTest {
    public static void main(String[] args){
        Integer[] arr = {5,2,7,3,9,10,8,6,1,4};
        quickSort(arr,0,arr.length-1);
        System.out.println(Arrays.toString(arr));
    }

    //排序方法-假设从小到大排序
    public static void quickSort(Integer[] arr,int low,int high){
        if(low < high){
            int part=partition(arr,low,high);
            //递归调用
            quickSort(arr,low,part-1);
            quickSort(arr,part+1,high);
        }
    }

    //划分方法
    private static int partition(Integer[] arr,int low,int high){
        //使用 r[low]作为枢轴元素
        int pivot = arr[low];
        //从两端交替向内扫描
        while(low < high){
            while(low<high && arr[high] >= pivot) {high--;}
            //将比 pivot 小的元素移向低端
            arr[low] = arr[high];
            while(low<high && arr[low] <= pivot){low++;}
            //将比 pivot 大的元素移向高端
            arr[high] = arr[low];
        }
        //设置枢轴
        arr[low]=pivot;
        //返回枢轴元素位置
        return low;
    }

}

空间效率:

快速排序需要一个堆栈来实现递归。若每次划分都将序列均匀分割为长度相近的两个子序列,则堆栈的最大深度为 log n,但是,在最坏的情况下,堆栈的最大深度为 n。

时间效率:

快速排序算法的运行时间依赖于划分是否平衡,即根据枢轴元素 pivot 将序列划分为两个子序列中的元素个数,而划分是否平衡又依赖于所使用的枢轴元素。下面我们在不同的情况下来分析快速排序的渐进时间复杂度。

快速排序的最坏情况是,每次进行划分时,在所得到的两个子序列中有一个子序列为空。在快速排序过程中,如果总是选择r[low]作为枢轴元素,则在待排序序列本身已经有序或逆向有序时,快速排序的时间复杂度为Ο(n2)。

快速排序的最好情况是,在每次划分时,都将序列一分为二,正好在序列中间将序列分成长度相等的两个子序列。此时,算法的时间复杂度T(n) = Θ(n log n)。

在平均情况下,快速排序的时间复杂度 T(n) = kn ㏑ n,其中 k 为某个常数,经验证明,在所有同数量级的排序方法中,快速排序的常数因子 k 是最小的。因此就平均时间而言,快速排序被认为是目前最好的一种内部排序方法。
快速排序的平均性能最好,但是,若待排序序列初始时已按关键字有序或基本有序,则快速排序退化为冒泡排序,其时间复杂度为Ο(n2)。为改进之,可以采取随机选择枢轴元素pivot的方法,具体做法是,在待划分的序列中随机选择一个元素然后与r[low]交换,再将r[low]作为枢轴元素,作如此改进之后将极大改进快速排序在序列有序或基本有序时的性能,在待排序元素个数n较大时,其运行过程中出现最坏情况的可能性可以认为不存在。

到此这篇关于Java快速排序案例讲解的文章就介绍到这了,更多相关Java快速排序详解内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java之jpa入门教程讲解

    JPA快速入门介绍 一:什么是JPA JPA的英文全称是Java PersistenceAPI, 目的是给Java开发者提供对象关系映射工具用于在 Java应用程序开发中来管理关系数据(RDBMS).JavaPersistence 包含下面三个部分: Java持久化API JPA查询语言 对象关系映射元数据 二:JPA有哪些框架提供了的实现 当前JPA提供厂商有Hibernate, Apache, Eclipse Link等,Google云计算平台 AppEngine也使 用了JPA作为持久层.

  • Java之String.format()方法案例讲解

    前言:  String.format()作为文本处理工具,为我们提供强大而丰富的字符串格式化功能,这里根据查阅的资料做个学习笔记,整理成如下文章,供后续复习查阅. 一. format()方法的两种重载形式: 1. format(String format, Object ... args) 该方法使用指定的格式字符串和参数返回一个格式化的字符串,格式化后的新字符串使用本地默认的语言环境. 2. format(Local l, String format, Pbject ... args) 其中,

  • Java前后端时间格式的转化方式

    JsonFormat.DateTimeFormat使用 从数据库获取时间传到前端进行展示的时候,我们有时候可能无法得到一个满意的时间格式的时间日期,在数据库中显示的是正确的时间格式,获取出来却变成了很丑的时间戳,@JsonFormat注解很好的解决了这个问题,我们通过使用@JsonFormat可以很好的解决:后台到前台时间格式保持一致的问题. 其次,另一个问题是,我们在使用WEB服务的时,可能会需要用到,传入时间给后台,比如注册新用户需要填入出生日期等,这个时候前台传递给后台的时间格式同样是不一

  • SpringMVC接收java.util.Date类型数据的2种方式小结

    SpringMVC接收java.util.Date类型数据 在Controller中如下定义方法 public PassQueryRequest trade(@ModelAttribute PassQueryRequest tradeRequest, @RequestParam(value="startDate", required=true)Date startDate, @RequestParam(value="endDate", required=true)D

  • Java BigDecimal案例详解

    引言 float和double类型的主要设计目标是为了科学计算和工程计算.他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的.然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合.但是,商业计算往往要求结果精确,这时候BigDecimal就派上大用场啦. 先看下面代码 public static void main(String[] args) { System.out.println(0.2 + 0.1); System.out.printl

  • java实现系统多级文件夹复制

    本文实例为大家分享了java实现系统多级文件夹复制的具体代码,供大家参考,具体内容如下 package com.jae; import java.io.*; //复制文件夹内的内容,包含多级文件夹 public class Test2 { public static void main(String[] args) throws Exception { //原文件夹地址 File resPath = new File("E:\\Java\\分享"); File destPath = n

  • java实现快速排序图文详解

    目录 高快省的排序算法 排序算法显神威 总结 高快省的排序算法 有没有既不浪费空间又可以快一点的排序算法呢?那就是"快速排序"啦!光听这个名字是不是就觉得很高端呢. 假设我们现在对"6 1 2 7 9 3 4 5 10 8"这个10个数进行排序.首先在这个序列中随便找一个数作为基准数(不要被这个名词吓到了,就是一个用来参照的数,待会你就知道它用来做啥的了).为了方便,就让第一个数6作为基准数吧.接下来,需要将这个序列中所有比基准数大的数放在6的右边,比基准数小的数放

  • Java之HashMap案例详解

    概述 这篇文章,我们打算探索一下Java集合(Collections)框架中Map接口中HashMap的实现.Map虽然是Collctions框架的一部分,但是Map并没有实现Collection接口,而Set和List是实现Collection接口的. 简单来说,HashMap主要通过key存储value值,并且提供了添加,获取和操作存储value的方法.HashMap的实现基于HashTable. HashMap内部呈现 Key-value对在内部是以buckets的方式存储在一起,最终成为

  • Java快速排序案例讲解

    交换类排序主要是通过两两比较待排元素的关键字,若发现与排序要求相逆,则"交换"之.在这类排序方法中最常见的是冒泡排序和快速排序.上一篇简单写了冒泡排序,这次简单写一写快速排序. 快速排序的思想: 快速排序是将分治法运用到排序问题中的一个典型例子,其基本思想是:通过一个枢轴(pivot)元素将 n 个元素的序列分为左.右两个子序列 Ll 和 Lr,其中子序列 Ll中的元素均比枢轴元素小,而子序列 Lr 中的元素均比枢轴元素大,然后对左.右子序列分别进行快速排序,在将左.右子序列排好序后,

  • java volatile案例讲解

    本篇来自java并发编程实战关于volatile的总结. 要说volatile,先得明白内存可见性.那我们就从内存可见性说起. 一.内存可见性 可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉.在单线程环境中,如果向某个变量先写入值,然后在没有其他写入操作的情况下读取这个变量,那么总能得到相同的值.这看起来很自然.然而,当读操作和写操作在不同的线程中执行时,情况却并非如此,这听起来或许有些难以接受.通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能

  • Java ResultSet案例讲解

    ResultSet ResultSet是我们使用jdbc连接时,查询的一个返回结果集,ResultSet resultSet = stmt.executeQuery(sql),下面就使用例子介绍ResultSet的使用 例子是通过jdbc连接查account表中的数据,然后用实体类Account封装起来,返回这个类的集合.  jdbc工具类代码 package com.lingaolu.Utils; import java.io.FileReader; import java.io.IOExce

  • Java对文件进行基本操作案例讲解

    File文件类 java.io.File是文件和目录的重要类(JDK6及以前是唯一) 目录也使用File类进行表示 File类与操作系统无关,但会受到操作系统的权限限制 常用方法 createNewFile , delete , exists , getAbsolutePath , getName , getParent , getPath isDirectory , isFile , length , listFiles , mkdir , mkdirs File不涉及到具体的文件内容.只会涉

  • Java之SSM中bean相关知识汇总案例讲解

    bean 的生命周期 对象创建 实例化Bean对象,默认选择无参构造方法,如果只有一个有参构造那么调用有参构造,如果只有多个有参构造那么报错,除非其中一个有参构造添加了@AutoWired注解: 设置Bean的属性: 依赖注入以及判断是否实现了Aware相关接口(BeanNameAware, BeanFactoryAware, ApplicationContextAware) 如果这个 Bean 关联了 BeanPostProcessor 接口,将会调用BeanPostProcessor.pos

  • Java插件扩展机制之SPI案例讲解

    目录 什么是SPI 与 接口类-实现类 提供的RPC 方式有什么区别? 假设我们需要实现RPC,是怎么做的? 那RPC究竟跟SPI什么关系? SPI的应用场景 怎么实现一个SPI? 中间件是怎么实现SPI的? Apollo-Client中的实现 JDBC中的实现 什么是SPI SPI ,全称为 Service Provider Interface,是一种服务发现机制.其为框架提供了一个对外可扩展的能力. 与 接口类-实现类 提供的RPC 方式有什么区别? 传统的接口类实现形式为如下 public

  • Java之SpringCloudAlibaba Sentinel组件案例讲解

    Sentinel 是什么 随着微服务的流行,服务和服务之间的稳定性变得越来越重要.Sentinel 以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度保护服务的稳定性. 官网:https://github.com/alibaba/Sentinel 中文官网:https://github.com/alibaba/Sentinel/wiki Sentinel与Hystrix的区别 由于Hystrix不再积极的开发,进入维护阶段,现在越来越多的开发者在项目中使用Spring Cloud Al

  • Java之网络编程案例讲解

    Java基础之网络编程 基本概念 IP:每个电脑都有一个IP地址,在局域网内IP地址是可变的. 网络通信协议:通信协议是对计算机必须遵守的规则,只有遵守这些规则,计算机之间才能进行通信.这就好比在道路中行驶的汽车一定要遵守交通规则一样,协议中对数据的传输格 式.传输速率.传输步骤等做了统一规定,通信双方必须同时遵守,最终完成数据交换. TCP协议(传输控制协议):是面向连接的传输层协议,应用程序在使用TCP之前,必须先建立TCP连接,在传输数据完毕后,必须释放已经建立的连接(跟打电话是否类似).

  • Java之IO流面试题案例讲解

    一.Java中IO流分为几种? 按照流的流向分,可以分为输入流和输出流: 按照操作单元分,可以分为字节流和字符流(字节流可以读写任何单位的数据,字符流只可以读写txt数据): 按照流的角色分,可以分为节点流和处理流: 二.IO中flush()和close()的区别 close()方法具备刷新功能,在关闭流之前就会先刷新缓冲区,将缓冲区的字节全部刷新到文件上,在关闭流.(close()方法包含一次flush()方法) flush()方法可以刷新,并且刷新之后可以继续写,而close()方法刷新之后

  • Java之常用类小结案例讲解

    Java常用类 包装类 由于Java语言中的基本类型不是面向对象,并不具备对象的性质,实际使用存在很多不便.Java在java.lang包中提供了八种基本类型对应的包装类,可以方便地将它们转化为对象进行处理,并且可以调用一些方法.Java中基本类型和包装类的对应关系如下表所示: 基本数据类型名称 包装类名称 byte Byte short Short int Integer long Long float Float double Double char Character boolean Bo

随机推荐