快排、双路快排、三路快排(java版)

import java.util.Date;
import java.util.Random;

/**
 * Created by maopengyu on 2019/11/27.
 * 快排、双路快排、三路快排
 * 参考:https://a1049145827.github.io/2018/10/15/Swift-%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F%E3%80%81%E5%8F%8C%E8%B7%AF%E5%BF%AB%E6%8E%92%E5%92%8C%E4%B8%89%E8%B7%AF%E5%BF%AB%E6%8E%92/
 */
public class QuickSort {
    private Random random = new Random();
    private int[] quickSort3Arr = new int[2];

    private void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    /**
     * 普通快排,时间复杂度O(nlogn),在数组有序或者重复元素较多时会退化到O(n2)
     * 当数组重复元素较多时,partition过程会将数组分成两个不平衡的部分(重复元素都在一边)
     * @param arr
     * @param start
     * @param end
     */
    public void quickSort(int[] arr, int start, int end) {
        if (start >= end) {
            return;
        }
        int mid = partition(arr, start, end);
        quickSort(arr, start, mid - 1);
        quickSort(arr, mid + 1 , end);
    }

    private int partition(int[] arr, int start, int end) {
        int r = start + random.nextInt(end - start + 1);
        swap(arr, r, start);
        int j = start;
        for (int i = start + 1; i <= end; i++) {
            if (arr[i] < arr[start]) {
                swap(arr, i, ++j);
            }
        }
        swap(arr, j, start);
        return j;
    }

    /**
     * 双路快排,优化重复元素多的情况,指针i和j从两端向中间逼近,
     * 将小于arr[mid]的值,放在左边;大于arr[mid]的值,放在右边,不会将重复元素放在一边,左右两变都可能包含相等的元素
     * @param arr
     * @param start
     * @param end
     */
    public void quickSort2(int[] arr, int start, int end) {
        if (start >= end) {
            return;
        }
        int mid = partition2(arr, start, end);
        quickSort(arr, start, mid - 1);
        quickSort(arr, mid + 1 , end);
    }

    private int partition2(int[] arr, int start, int end) {
        int r = start + random.nextInt(end - start + 1);
        swap(arr, r, start);
        int i = start + 1;
        int j = end;

        while (true) {
            // 这里不能arr[i] <= arr[start] 否则如果连续出现多个==的情况,则会把这些值归到一边
            while (i <= end && arr[i] < arr[start]) {
                i++;
            }
            // 这里不能arr[j] >= arr[start] 否则如果连续出现多个==的情况,则会把这些值归到一边
            while (j >= start + 1 && arr[j] > arr[start]) {
                j--;
            }
            if (i >= j) {
                break;
            }
            swap(arr, i, j);
            i++;
            j--;
        }

        swap(arr, j, start);
        return j;
    }

    /**
     * 三路快排,将数据按arr[mid]分为,小于、等于、大于三个区域,
     * 递归时,只需处理小于和大于的区域,减少了一次处理的元素
     * @param arr
     * @param start
     * @param end
     */
    public void quickSort3(int[] arr, int start, int end) {
        if (start >= end) {
            return;
        }
        int[] mid = partition3(arr, start, end);
        quickSort3(arr, start, mid[0]);
        quickSort3(arr, mid[1], end);
    }

    private int[] partition3(int[] arr, int start, int end) {
        int r = start + random.nextInt(end - start + 1);
        swap(arr, r, start);

        int lt = start; //arr[start+1, lt] < arr[start]
        int i = start + 1; //arr[lt+1, i] < arr[start]
        int gt = end + 1; //arr[gt, end] > arr[start]

        while (i < gt) {
            if (arr[i] < arr[start]) {
                swap(arr, i, lt + 1);
                i++;
                lt++;
            }else if (arr[i] > arr[start]) {
                swap(arr, i, gt - 1);
                gt--;
            }else {
                i++;
            }
        }
        swap(arr, lt, start);

        quickSort3Arr[0] = lt - 1;
        quickSort3Arr[1] = gt;

        return quickSort3Arr;
    }

    public static void main(String[] args) {
        Random random1 = new Random();
        int[] arr1 = new int[50000];
        int[] arr2 = new int[50000];
        int[] arr3 = new int[50000];
        for (int i = 0; i < 50000; i++) {
            int num = random1.nextInt(10);
            arr1[i] = num;
            arr2[i] = num;
            arr3[i] = num;
        }

        QuickSort quickSort = new QuickSort();

        Date start1 = new Date();
        quickSort.quickSort(arr1, 0, arr1.length - 1);
        Date end1 = new Date();
        System.out.println((end1.getTime() - start1.getTime()));
        StringBuilder sb1 = new StringBuilder();
        for (int i : arr1) {
            sb1.append(i);
        }

        Date start2 = new Date();
        quickSort.quickSort2(arr2, 0, arr3.length - 1);
        Date end2 = new Date();
        System.out.println((end2.getTime() - start2.getTime()));
        StringBuilder sb2 = new StringBuilder();
        for (int i : arr2) {
            sb2.append(i);
        }

        Date start3 = new Date();
        quickSort.quickSort3(arr3, 0, arr3.length - 1);
        Date end3 = new Date();
        System.out.println((end3.getTime() - start3.getTime()));
        StringBuilder sb3 = new StringBuilder();
        for (int i : arr3) {
            sb3.append(i);
        }

        if (sb1.toString().equals(sb2.toString()) && sb2.toString().equals(sb3.toString())) {
            System.out.println("true");
        }
        /**
         * 结果:
         * 108
         * 70
         * 7
         * true
         */
    }
}

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

推荐阅读更多精彩内容