快速排序的基本思路是,每次选定数列中的一个基准数,将小于基准数的数字都放到基准数左边,大于基准数的数字都放到基准数右边。然后再分别对基准数左右的两个数列分别重复以上过程。仍以4 3 6 2 7 1 5为例。

选定最左侧数字4为基准数,首先从右开始向左找小于4的数,找到第一个数1后停止。然后从左开始向右找到第一个大于4的数,即6。

交换这两个数的位置,得到

继续寻找,仍然从右边开始,从上一步找到1的位置向左寻找小于4的数,找到2停止。然后从左边找到6的位置向右找大于4的数。右移一格后,和右侧来的“探路者”相遇了,这意味着这一轮排序结束。

最后把结束位置的数和基准数交换

观察完成后的数列,可以看到以基准数4为分界线,左边的数全都比4小,右边的数全都比4大。接下来分别对左边的2 3 1和右边的7 6 5重复上面的排序步骤。

2 3 1

以2为基准数 -> 2 1 3 -> 1 2 3

7 6 5

以7为基准数 -> 5 6 7

我们例子中的数字较少,如果数列足够长,对第一次排序后得到的子数列排序,将再得到两个子数列,然后再一分为二、二分为四。。。直到以基准数拆分后两边都只剩下一个数字。首先来看递归形式的实现代码

  1. public class QuickSort {
  2. public void sort(int left, int right, int... numbers) {
  3. if (left >= right) {
  4. return;
  5. }
  6. int temp = numbers[left];
  7. int t = 0;
  8. int i = left;
  9. int j = right;
  10. while (i != j) {
  11. // 先从右往左找
  12. while (numbers[j] >= temp && i < j)
  13. j--;
  14. // 再从左往右找
  15. while (numbers[i] <= temp && i < j)
  16. i++;
  17. // 交换两个数在数组中的位置
  18. if (i < j) {
  19. t = numbers[i];
  20. numbers[i] = numbers[j];
  21. numbers[j] = t;
  22. }
  23. }
  24. // 将基准数归位
  25. numbers[left] = numbers[i];
  26. numbers[i] = temp;
  27. sort(left, i - 1, numbers);
  28. sort(i + 1, right, numbers);
  29. }
  30. }

测试代码

  1. public static void main(String[] args) {
  2. int[] numbers = new int[] { 4, 3, 6, 2, 7, 1, 5 };
  3. new QuickSort().sort(0, numbers.length - 1, numbers);
  4. System.out.print("after: ");
  5. for (int i = 0; i < numbers.length; i++) {
  6. System.out.print(numbers[i] + "  ");
  7. }
  8. System.out.println();
  9. }

输出

  1. after: 1  2  3  4  5  6  7

另一种实现方式是使用栈代替递归

  1. public void sortWithoutRecursion(int left, int right, int... numbers) {
  2. LinkedList<Integer> stack = new LinkedList<>();
  3. int index;
  4. stack.push(left);
  5. stack.push(right);
  6. while (!stack.isEmpty()) {
  7. right = stack.pop();
  8. left = stack.pop();
  9. index = partition(left, right, numbers);
  10. if (left < index - 1) {
  11. stack.push(left);
  12. stack.push(index - 1);
  13. }
  14. if (right > index + 1) {
  15. stack.push(index + 1);
  16. stack.push(right);
  17. }
  18. }
  19. }
  20. public int partition(int left, int right, int... numbers) {
  21. int temp = numbers[left];
  22. while (left < right) {
  23. while (numbers[right] >= temp && left < right)
  24. right--;
  25. numbers[left] = numbers[right];
  26. while (numbers[left] <= temp && left < right)
  27. left++;
  28. numbers[right] = numbers[left];
  29. }
  30. numbers[left] = temp;
  31. return left;
  32. }

Java与算法之(2) - 快速排序的更多相关文章

  1. java排序算法(五):快速排序

    java排序算法(五):快速排序 快速排序是一个速度非常快的交换排序算法,它的基本思路很简单,从待排的数据序列中任取一个数据(如第一个数据)作为分界值,所有比它小的元素放到左边.所有比它大的元素放到右 ...

  2. Java排序算法之快速排序

    Java排序算法之快速排序 快速排序(Quicksort)是对冒泡排序的一种改进. 快速排序由C. A. R. Hoare在1962年提出.它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分 ...

  3. java排序算法之冒泡排序和快速排序

    总结一下Java排序算法,以便记忆. 各类排序的时间复杂度: 排序方法 时间复杂度(平均) 时间复杂度(最坏) 时间复杂度(最好) 空间复杂度 稳定性 复杂性 直接插入排序 O(n2)O(n2) O( ...

  4. 算法相关——Java排序算法之快速排序(三)

    0. 前言 本系列文章将介绍一些常用的排序算法.排序是一个非常常见的应用场景,也是开发岗位面试必问的一道面试题,有人说,如果一个企业招聘开发人员的题目中没有排序算法题,那说明这个企业不是一个" ...

  5. 常用Java排序算法

    常用Java排序算法 冒泡排序 .选择排序.快速排序 package com.javaee.corejava; public class DataSort { public DataSort() { ...

  6. (转)java 排序算法

    排序算法汇总(java实现,附源代码)   整理系统的时候发现了原来写的各种算法的总结,看了一下,大吃一惊,那时候的我还如此用心,具体的算法,有的已经模糊甚至忘记了,看的时候就把内容整理出来,顺便在熟 ...

  7. Java TimSort算法 源码 笔记

    本来准备看Java容器源码的.但是看到一开始发现Arrays这个类我不是很熟,就顺便把Arrays这个类给看了.Arrays类没有什么架构与难点,但Arrays涉及到的两个排序算法似乎很有意思.那顺便 ...

  8. java排序算法(一):概述

    java排序算法(一)概述 排序是程序开发中一种非常常见的操作,对一组任意的数据元素(活记录)经过排序操作后,就可以把它们变成一组按关键字排序的一组有序序列 对一个排序的算法来说,一般从下面三个方面来 ...

  9. java排序算法(四):冒泡排序

    java排序算法(四):冒泡排序 冒泡排序是计算机的一种排序方法,它的时间复杂度是o(n^2),虽然不及堆排序.快速排序o(nlogn,底数为2).但是有两个优点 1.编程复杂度很低.很容易写出代码 ...

随机推荐

  1. Spring Boot [使用 Druid 数据库连接池]

    导读 最近一段时间比较忙,以至于很久没有更新Spring Boot系列文章,恰好最近用到Druid, 就将Spring Boot 使用 Druid作为数据源做一个简单的介绍. Druid介绍: Dru ...

  2. if;脚本中退出语句:exit 数字,用$?查时为exit设置的数字,此数字为程序执行完后的返回数据,可以通过此方法自动设定

    if [ 条件 ];then 代码 fi if [ 条件 ] then 代码 fi [root@localhost ~]# df 文件系统 1K-块 已用 可用 已用% 挂载点 /dev/sda5 % ...

  3. Node.js前言

    最近在学Node.js,所以学到一点东西就更新在上面吧,如果有错误,欢迎大家指正.

  4. bzoj 4872: [Shoi2017]分手是祝愿

    Description Zeit und Raum trennen dich und mich. 时空将你我分开.B 君在玩一个游戏,这个游戏由 n 个灯和 n 个开关组成,给定这 n 个灯的初始状态 ...

  5. bzoj 3597: [Scoi2014]方伯伯运椰子

    Description Input 第一行包含二个整数N,M 接下来M行代表M条边,表示这个交通网络 每行六个整数,表示Ui,Vi,Ai,Bi,Ci,Di 接下来一行包含一条边,表示连接起点的边 Ou ...

  6. 3、树莓派的配置:改静态IP、连接ssh、安装中文字体、安装谷歌输入法、增加USB电流、修改触摸屏分辨率、扩展sd卡空间、修复vi和vim乱码问题、安装配置远程桌面vnc

    本博文仅作本人操作过程的记录,留作备忘.自强不息 QQ1222698 1.连接上HDMI线,插上触摸屏,插上键盘,鼠标,网线,启动.系统正常启动,但是一直闪烁,不停的黑屏,是由于触摸屏的usb口供电不 ...

  7. 通过js添加的元素点击事件无法触发

    var blk_have ='<div class="sw-off"></div>'; $('#blk').prepend(blk_have); $(doc ...

  8. idea激活网站地址,亲测可用(windows7,idea 2016)

    help-register-license server,然后输入 http://idea.iteblog.com/key.php

  9. Python的伪私有属性

    什么是伪私有属性? 在Python中,没有类似 private 之类的关键字来声明私有方法或属性. Python中要声明私有属性,需要在属性前加上双下划线(但是结尾处不能有双下划线),如:self._ ...

  10. CheckForIllegalCrossThreadCalls = false

    多线程程序中,新创建的线程不能访问UI线程创建的窗口控件,这时如果想要访问窗口的控件,发现无法对其控制. 这时可将窗口构造函数中的CheckForIllegalCrossThreadCalls设置为f ...