【算法】排序(五)快速排序

正文之前

快速排序(英语:Quicksort),又称划分交换排序(partition-exchange sort),一种排序算法,最早由东尼 * 霍尔提出。在平均状况下,排序n个项目要O(nlogn)次比较,在最坏情况下则需要O(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他O(nlogn)算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。              ——Wikipedia


本文将介绍以下内容

排序原理
算法实现(JAVA)
测试阶段
算法分析

正文

排序原理

和归并排序划清界限:

  • 归并排序:将一个数组分成两个字数组,分别排序两部分,将有序的子数组归并得到整个有序数组

  • 快速排序:将一个数组分成两个字数组,分别排序两部分,当两个子数组有序时,整个数组自然就有序了

快速排序使用一个切分元素来划分数组,切分元素左边的数组元素小于切分元素,右边的数组元素大于于切分元素,所以两个子数组有序就会得到整个有序的数组

算法实现

1. 切分数组
private static int partition(int[] a, int low, int high){
        int i = low, j = high + 1;              //由两边向中间扫描
        int p = a[low];                         //切分数组的元素
        while(true){
            while(a[++i] < p){                  // i 的值会一直递增至 a[++i] >= p
                if(i == high){                  //扫描结束
                    break;
                }
            }
            while(a[--j] > p){                  // j 的值会一直递减至 a[++i] >= p
                if(j == low){                   //扫描结束
                    break;
                }
            }

            if(i >= j){                         // j 的位置就是切分元素在有序数组中的位置
                break;
            }

            int temp = a[i];                    //交换元素顺序
            a[i] = a[j];
            a[j] = temp;
        }

        int temp = a[low];                      //将切分元素交换至中间位置
        a[low] = a[j];
        a[j] = temp;

        return j;
    }
2. 数组排序

这一部分的代码和归并排序的排序代码相似

private static void quickSort(int[] a){
        sort(a, 0, a.length - 1);
    }

    private static void sort(int[] a, int lo, int hi){
        if(hi <= lo){
            return ;
        }
        int j = partition(a, lo, hi);
        sort(a, lo, j - 1);
        sort(a, j + 1, hi);
    }

sort方法递归调用自己,将数组划分至最小,每次都将子序列中的第一个元素作为切分元素,来将数组排序

整个排序过程的代码:
public class QuickSort {

    private static int partition(int[] a, int low, int high){
        int i = low, j = high + 1;              //由两边向中间扫描
        int p = a[low];                         //切分数组的元素
        while(true){
            while(a[++i] < p){                  // i 的值会一直递增至 a[++i] >= p
                if(i == high){                  //扫描结束
                    break;
                }
            }
            while(a[--j] > p){                  // j 的值会一直递减至 a[++i] >= p
                if(j == low){                   //扫描结束
                    break;
                }
            }

            if(i >= j){                         // j 的位置就是切分元素在有序数组中的位置
                break;
            }

            int temp = a[i];                    //交换元素顺序
            a[i] = a[j];
            a[j] = temp;
        }

        int temp = a[low];                      //将切分元素交换至中间位置
        a[low] = a[j];
        a[j] = temp;

        return j;
    }

    private static void quickSort(int[] a){
        sort(a, 0, a.length - 1);
    }

    private static void sort(int[] a, int lo, int hi){
        if(hi <= lo){
            return ;
        }
        int j = partition(a, lo, hi);
        sort(a, lo, j - 1);
        sort(a, j + 1, hi);
    }
}

测试阶段

public static void main(String[] args){
        int[] a = new int[10];
        for (int i = 0; i < 10; i++) {
            a[i] = (int)(Math.random() * 100);
            System.out.print(a[i] + " ");
        }
        quickSort(a);
        System.out.println();
        for (int i = 0; i < 10; i++) {
            System.out.print(a[i] + " ");
        }
    }

生成10个随机数字并调用快速排序方法,最后输出结果:

算法分析

1. 特点

快速排序实现简单,应用广泛,比一般算法要快很多,并且是原地排序(借助辅助栈)

2. 时间复杂度
  1. 设数组的长度为N,用 T(N) 表示排序一个长度为N的数组所需要的比较次数,可想而知,T(0) 和 T(1) 为0

  2. 切分的成本为N + 1,左子数组排序的平均成本为(C1 + C2 + ... + CN - 2 + CN - 1)/N,右子数组排序的平均成本为(CN - 1 + CN - 2 + ... + C2 + CN)/N

  3. CN = N + 1 + (C1 + C2 + ... + CN - 2 + CN - 1)/N + (CN - 1 + CN - 2 + ... + C2 + CN)/N

  4. 经过化简之后得到:CN ~ 2(N + 1)(1/3 + 1/4 + ... + 1/(N + 1))

  5. 积分得到CN ~ 2NlogN

所以,算法复杂度为 O(nlogn)

3. 稳定性

举个例子,一个数组a = [6,4,3,2,3,7,8,7,9],a[0]和a[4]交换,第二个 3 就移动到了第一个 3 的前面,所以是不稳定的,不稳定性体现在切分元素交换的时候

关于快速排序的介绍就到这里了,谢谢!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容

  • 日月是报应体 月日交替红晕起 粉红如那少女羞 这是不让把觉睡? 人身不是神仙体 寄于人身没法仙 万般神通不能使 成...
    纵情嬉戏天地间阅读 194评论 0 0
  • 曾经流行的某个段子:握住老婆的手,就像左手握右手,一点感觉都没有。似乎是说夫妻之情极易平淡如水;但从另一角度又恰巧...
    Kaliraja阅读 1,407评论 0 0
  • 原创四十篇(15/02/2017) ——从做“应用题”到做“选择题” 在中国这样的大环境中,绝大多数的人都习惯了自...
    许文辉阅读 926评论 0 1
  • 小编收集整理的项目都是经过小编本人亲自运行测试(有的项目bug之多,谁改谁知道,但是在小编的修改下都是可以运行的,...
    摸着石头过河_崖边树阅读 368评论 0 0
  • 11看不见的努力!—你看到的上面这样的照片其实是下面这样拍出来的。所以,我们要感谢那些“看不见的努力”。
    geqi阅读 269评论 6 4