java实现的比较不错的快速排序

本文为原创文章,转载请注明出处,谢谢你……
喜欢java并发编程的请加群:736156823
开始-->

import java.util.concurrent.ThreadLocalRandom;

public class QSort {

    // 选择枢轴时候要求数据个数大于3
    private static final int OFF_SIT = 3;
    // 选择快排还是插入的界限
    private static final int INSERT_FLAG = 13;

    // 数组的有效下标
    public void sort(int[] array, int left, int right) {
        // 一些无用的校验
        if (null == array) {
            return;
        } else if (array.length <= 1) {
            return;
        } else if (left < 0 || right < 0) {
            return;
        } else if (right - left <= 1) {
            return;
        } else {
            quick(array, left, right);
        }
    }

    private void quick(int[] array, int left, int right) {
        // 如果数组中的数据太少,使用插入排序
        // 根据下面选择枢轴的方法,太少也是不允许的
        // 大量实验证明,数据在5到20内的数据,插入排序快于快速排序
        // 这里选择的是13,实验发现13比较好
        if (left + OFF_SIT <= right) {
            if (left + INSERT_FLAG <= right) {
                int p = partition(array, left, right);
                // 实际比较是从left-1,right-2开始的
                // 因为left,right-1,right三者已经有序
                // 具体参考枢轴的选择策略partition
                int i = left, j = right - 1;
                for (; ; ) {
                    for (; ; ) {
                        // 直接加就好了,不需要判断是否越界
                        // 原因就是有三个数已经控制了边界
                        i = i + 1;
                        // 这里说明下:
                        // 为什么大于或者等于都要停止指针移动?
                        // 因为大量实验发现,当等于的时候也停止指针移动是较好的
                        // 从工程角度看两个指针都要判断等于才行
                        // 因为如果只有一边判断会造成不平衡性问题
                        // 也就是因为快排每趟都会分大于小于枢轴的两个集合的
                        // 如果只有一边判断等于那么很容易将等于枢轴的数分到一个集合中
                        // 造成了另一个集合没有等于枢轴的数
                        // 从工程学角度是不合理的
                        if (array[i] >= p) {
                            break;
                        }
                    }
                    for (; ; ) {
                        j = j - 1;
                        if (array[j] <= p) {
                            break;
                        }
                    }
                    // i>=j,说明都比较完了,应该跳出循环
                    if (i < j) {
                        swap(array, i, j);
                    } else {
                        break;
                    }
                }
                // {left,2,3,4,5,i,i+1,8,9,right-1,right}
                // 对照数组就很明了了
                swap(array, i, right - 1);
                // 是一个递归调用,后续考虑实现非递归调用的高效算法
                // 因为是要实现并发的快排的
                quick(array, left, i - 1);
                quick(array, i + 1, right);
            } else {
                insertion(array, left, right);
            }
        } else {
            insertion(array, left, right);
        }
    }

    // 枢轴的选择,采用中位数法
    // 1)对头,中,尾三个数进行排序
    // 2)将已经排好序的中间位置的数与倒数第二个数交换
    // 3)这样做的好处是:排序的部分就是第二个位置与倒数第三个位置的中间部分
    // 中间没有枢轴,移动指针的时候无需判断越界
    // 因为两边的边界已经确定了
    // 这样还有个好处就是数组中已经有三个数的排好序的了
    // 并且这三个数不需要参与移动
    // 仅仅作为一些判断标志以及控制
    private int partition(int[] array, int left, int right) {
        int c = (left + right) / 2;
        if (array[left] > array[c]) {
            swap(array, left, c);
        }
        if (array[left] > array[right]) {
            swap(array, left, right);
        }
        if (array[c] > array[right]) {
            swap(array, c, right);
        }
        swap(array, c, right - 1);
        return array[right - 1];
    }

    private void swap(int[] array, int left, int right) {
        int temp = array[left];
        array[left] = array[right];
        array[right] = temp;
    }

    // 插入排序
    public void insertion(int[] array, int left, int right) {
        first(array, left, right);
        for (int i = left + 2; i <= right; i++) {
            int temp = array[i];
            int j = i;
            for (; temp < array[j - 1]; j--) {
                array[j] = array[j - 1];
            }
            array[j] = temp;
        }
    }

    // 这里的选择最小数也是控制手段,简单的选择,并不是像冒泡那样
    // 正确方法还是参考之前的具体算法吧
    private void first(int[] array, int left, int right) {
        int sm = left;
        for (int i = left; i <= right; i++) {
            if (array[i] < array[sm]) {
                sm = i;
            }
        }
        // 仅仅将最小的数置于最开始的位置
        swap(array, left, sm);
    }

    // 至于时间复杂度,空间复杂度大家百度吧,或者参考算法导论
    public static void main(String args[]) {
        QSort qs = new QSort();
        // 每次都是生成的不同的随机数
        // 如果使用同一组数,这样利用硬件特性,耗费的时间会更少
        // 可以试试
        ThreadLocalRandom random = ThreadLocalRandom.current();
        for (int t = 0; t < 100; t++) {
            int nums[] = new int[99999999];
            for (int i = 0; i < 99999999; i++) {
                int r = random.nextInt(999999999);
                nums[i] = r;
            }
            System.out.println("quick sort init finish ......");
            //qs.insertion(nums,0,nums.length-1);
            long start = System.nanoTime();
            qs.sort(nums, 0, nums.length - 1);
            long finish = System.nanoTime();
            System.out.println("quick sort finish ......cust nano time=" + (finish - start));
            for (int i = 0; i < nums.length - 1; i++) {
                if (nums[i] > nums[i + 1]) {
                    throw new IllegalStateException();
                }
            }
            System.out.println("...... check finish ,time=" + t + ",  ......");
        }
    }

}

喜欢java并发编程的请加群:736156823

<--结束
有问题欢迎指正,这是新鲜出炉的
本文为原创文章,转载请注明出处,谢谢你……

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,387评论 25 707
  • 请让我看看你的手 你的手犹如生满铁锈 原本湿润的皮肤与氧气厮磨 与老茧相守 你撑起了这个家 却嶙峋了双手 请让我看...
    填我十万八千梦阅读 303评论 0 9
  • 娟子在结束了繁忙的一天的医院工作,就奔赴了闺蜜佳丽的约,看着梨花带雨的标准的鹅蛋脸,娟子知道,这次,佳丽是真真的伤...
    漂泊的思念阅读 533评论 0 6
  • 新年开跑第一天 2019年核心目标:变美 变瘦 变有钱! 每天只做三件事 :吃饭 睡觉 上首席!
    美力私教森森张阅读 187评论 1 0