高快省的排序算法

有没有既不浪费空间又能够快一点的排序算法呢?那就是“高速排序”啦!

光听这个名字是不是就认为非常高端呢。

如果我们如今对“6 1 2 7 9 3 4 5 10 8”这个10个数进行排序。

首先在这个序列中随便找一个数作为基准数(不要被这个名词吓到了,就是一个用来參照的数,待会你就知道它用来做啥的了)。为了方便,就让第一个数6作为基准数吧。接下来,须要将这个序列中所有比基准数大的数放在6的右边,比基准数小的数放在6的左边,相似以下这种排列:

3 1 2 5 4 6 9 7 10 8

在初始状态下。数字6在序列的第1位。我们的目标是将6挪到序列中间的某个位置,如果这个位置是k。如今就须要寻找这个k。而且以第k位为分界点,左边的数都小于等于6。右边的数都大于等于6。

想一想。你有办法能够做到这点吗?

排序算法显神威

方法事实上非常easy:分别从初始序列“6 1 2 7 9 3 4 5 10 8”两端開始“探測”。先从找一个小于6的数,再从找一个大于6的数,然后交换他们。这里能够用两个变量i和j。分别指向序列最左边和最右边。

我们为这两个变量起个好听的名字“哨兵i”和“哨兵j”。

刚開始的时候让哨兵i指向序列的最左边(即i=1)。指向数字6。

让哨兵j指向序列的最右边(即=10),指向数字。



首先哨兵j開始出动。

由于此处设置的基准数是最左边的数。所以须要让哨兵j先出动,这一点非常重要(请自己想一想为什么)。

哨兵j一步一步地向左挪动(即j–),直到找到一个小于6的数停下来。接下来哨兵i再一步一步向右挪动(即i++),直到找到一个数大于6的数停下来。最后哨兵j停在了数字5面前,哨兵i停在了数字7面前。





如今交换哨兵i和哨兵j所指向的元素的值。交换之后的序列例如以下:

6 1 2 5 9 3 4 7 10 8





到此。第一次交换结束。接下来開始哨兵j继续向左挪动(再友情提醒,每次必须是哨兵j先出发)。他发现了4(比基准数6要小,满足要求)之后停了下来。哨兵i也继续向右挪动的,他发现了9(比基准数6要大,满足要求)之后停了下来。此时再次进行交换,交换之后的序列例如以下:

6 1 2 5 4 3 9 7 10 8

第二次交换结束,“探測”继续。哨兵j继续向左挪动,他发现了3(比基准数6要小,满足要求)之后又停了下来。哨兵i继续向右移动,糟啦!此时哨兵i和哨兵j相遇了,哨兵i和哨兵j都走到3面前。

说明此时“探測”结束。我们将基准数6和3进行交换。

交换之后的序列例如以下:

3 1 2 5 4 6 9 7 10 8





到此第一轮“探測”真正结束。

此时以基准数6为分界点,6左边的数都小于等于6,6右边的数都大于等于6。回想一下刚才的过程,事实上哨兵j的使命就是要找小于基准数的数,而哨兵i的使命就是要找大于基准数的数,直到i和j碰头为止。

OK,解释完成。如今基准数6已经归位。它正优点在序列的第6位。此时我们已经将原来的序列,以6为分界点拆分成了两个序列,左边的序列是“3 1 2 5 4”。右边的序列是“9 7 10 8”。接下来还须要分别处理这两个序列。由于6左边和右边的序列眼下都还是非常混乱的。

只是不要紧,我们已经掌握了方法,接下来仅仅要模拟刚才的方法分别处理6左边和右边的序列就可以。如今先来处理6左边的序列现吧。

左边的序列是“3 1 2 5 4”。

请将这个序列以3为基准数进行调整,使得3左边的数都小于等于3,3右边的数都大于等于3。

好了開始动笔吧

如果你模拟的没有错,调整完成之后的序列的顺序应该是:

2 1 3 5 4

OK。如今3已经归位。接下来须要处理3左边的序列“2 1”和右边的序列“5 4”。对序列“2 1”以2为基准数进行调整,处理完成之后的序列为“1 2”。到此2已经归位。

序列“1”仅仅有一个数,也不须要进行不论什么处理。至此我们对序列“2 1”已所有处理完成,得到序列是“1 2”。序列“5 4”的处理也仿照此方法,最后得到的序列例如以下:

1 2 3 4 5 6 9 7 10 8

对于序列“9 7 10 8”也模拟刚才的过程。直到不可拆分出新的子序列为止。终于将会得到这种序列,例如以下

1 2 3 4 5 6 7 8 9 10

到此。排序全然结束。

细心的同学可能已经发现。高速排序的每一轮处理事实上就是将这一轮的基准数归位,直到所有的数都归位为止。排序就结束了。

以下上个霸气的图来描写叙述下整个算法的处理过程。

这是为什么呢?

高速排序之所比較快。由于相比冒泡排序,每次交换是跳跃式的。每次排序的时候设置一个基准点,将小于等于基准点的数所有放到基准点的左边。将大于等于基准点的数所有放到基准点的右边。这样在每次交换的时候就不会像冒泡排序一样每次仅仅能在相邻的数之间进行交换,交换的距离就大的多了。因此总的比較和交换次数就少了。速度自然就提高了。当然在最坏的情况下,仍可能是相邻的两个数进行了交换。

因此高速排序的最差时间复杂度和冒泡排序是一样的都是O(N2),它的平均时间复杂度为O(NlogN)。事实上高速排序是基于一种叫做“二分”的思想。我们后面还会遇到“二分”思想,到时候再聊。

先上代码,例如以下

代码实现:

public class QuickSort {
public static void quickSort(int[] arr,int low,int high){
int i,j,temp,t;
if(low>high){
return;
}
i=low;
j=high;
//temp就是基准位
temp = arr[low]; while (i<j) {
//先看右边,依次往左递减
while (temp<=arr[j]&&i<j) {
j--;
}
//再看左边,依次往右递增
while (temp>=arr[i]&&i<j) {
i++;
}
//如果满足条件则交换
if (i<j) {
t = arr[j];
arr[j] = arr[i];
arr[i] = t;
} }
//最后将基准为与i和j相等位置的数字交换
arr[low] = arr[i];
arr[i] = temp;
//递归调用左半数组
quickSort(arr, low, j-1);
//递归调用右半数组
quickSort(arr, j+1, high);
} public static void main(String[] args){
int[] arr = {10,7,2,4,7,62,3,4,2,1,8,9,19};
quickSort(arr, 0, arr.length-1);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
输出为
1
2
2
3
4
4
7
7
8
9
10
19
62

原文地址:http://developer.51cto.com/art/201403/430986.htm

高速排序——JAVA实现(图文并茂)的更多相关文章

  1. 高速排序java语言实现

    本博客不再更新,很多其它精彩内容请訪问我的独立博客 高速排序是非常重要的排序算法,可是我在学的时候发现网上没有特别好的样例所以自己动手写了一个. 自己动手丰衣足食. package sort; imp ...

  2. java:高速排序算法与冒泡排序算法

     Java:高速排序算法与冒泡算法 首先看下,冒泡排序算法与高速排序算法的效率: 例如以下的是main方法: /**   *  * @Description:  * @author:cuiyaon ...

  3. 高速排序(Java版)

    package com.love.test; import java.util.Scanner; /** * @author huowolf *高速排序实现 *快排是十分优秀的排序算法. *核心:分治 ...

  4. 排序算法之高速排序(Java)

    //高速排序 public class Quick_Sort { // 排序的主要算法 private int Partition(int[] data, int start, int end) { ...

  5. 高速排序及优化(Java版)

    高速排序(Quicksort)是对冒泡排序的一种改进. 高速排序由C. A. R. Hoare在1962年提出. 一次高速排序具体过程: 选择数组第一个值作为枢轴值. 代码实现: package Qu ...

  6. 插入排序、冒泡排序、选择排序、希尔排序、高速排序、归并排序、堆排序和LST基数排序——C++实现

    首先是算法实现文件Sort.h.代码例如以下: <pre name="code" class="java">/* * 实现了八个经常使用的排序算法: ...

  7. 希尔排序及希尔排序java代码

    原文链接:http://www.orlion.ga/193/ 由上图可看到希尔排序先约定一个间隔(图中是4),然后对0.4.8这个三个位置的数据进行插入排序,然后向右移一位对位置1.5.9进行插入排序 ...

  8. 排序(5)---------高速排序(C语言实现)

    继shell发明了shell排序过后呢,各位计算机界的大牛们又開始不爽了,为什么他能发明.我就不能发明呢.于是又有个哥们蹦出来了.哎...那么多排序,就木有一个排序是中国人发明的.顺便吐槽一下,一百年 ...

  9. 高速排序-c++(分别用数组和容器实现)

    /********************************************************************** *版权全部 (C)2014, cheng yang. * ...

随机推荐

  1. Android 经常使用工作命令mmm,mm,m,croot,cgrep,jgrep,resgrep,godir

    官方定义: Invoke ". build/envsetup.sh" from your shell to add the following functions to your ...

  2. Windows Phone相关

    Windows Phone IP over USB Transport (IpOverUsbSvc) is not running 进“服务”搜索 “Windows Phone IP Over USB ...

  3. <Sicily>Pythagorean Proposition

    一.题目描述 One day, WXYZ got a wooden stick, he wanted to split it into three sticks and make a right-an ...

  4. redis动态修改参数

    通过 config get 命令可以查看参数. 通过config set 可以修改某些参数 动态关闭redis的aof功能:(不要忘了也修改配置文件中的aof选项使其保持一致) 127.0.0.1:6 ...

  5. 【Git 五】TortoiseGit中SSH密钥的配置方法

    注意:我用的 TortoiseGit 版本是 2.6 的. 一.找到安装目录下的 bin 目录 二.点击 puttygen.exe 三.点击 Generate 生成完毕之后,将 public key ...

  6. cmd 操作命令

    1)cd 操作文件目录的 cd path #进入path cd / #返回到当前盘符的根目录 cd .. #返回到上级目录 2)dir 显示当前目录 dir #显示当前目录下的文件夹 dir path ...

  7. 【习题 8-20 UVA-1620】Lazy Susan

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 会发现,如果把连续4个数字进行一次翻转的话. 假设这连续的4个数字的逆序数为x; 那么翻转过后,逆序数就会变成6-x; (最多6个逆 ...

  8. Myeclipse学习总结(4)——Eclipse常用开发插件

    (1)    AmaterasUML         介绍:Eclipse的UML插件,支持UML活动图,class图,sequence图,usecase图等:支持与Java class/interf ...

  9. Spring Cloud学习笔记【十】配置中心(消息驱动刷新配置)

    上一篇中讲到,如果需要客户端获取到最新的配置信息需要执行refresh,我们可以利用 Webhook 的机制每次提交代码发送请求来刷新客户端,当客户端越来越多的时候,需要每个客户端都执行一遍,这种方案 ...

  10. 怎么打开/查看MySQL的SQL记录

    mysql在执行sql的时候会在日志当中记录很多信息,当然包括执行的所有语句.下面以使用navicat for mysql为例,来展示一下如何打开/查看MySQL的SQL记录: 打开navicat f ...