三种快速排序算法的学习和心得(java)

        快速排序是目前比较常用的排序算法,也是需要掌握的排序算法,光听它的名字就知道这种算法的运算速度很快,没错!这是目前已知的算法中平均排序速率最快的。当然这里是说只使用一种排序算法比较的前提下。

快速排序算法主要分为以下几步:

1)选择基准值

2)双指针操作将小于基准的放左边,大于的放右边

3)重复2操作,直至结束

快速排序算法是利用排序轮数不变,每轮排序只比较了log2n次来提高排序速度,这与堆排序,归并排序的原理类似。但是快速排序没有初始建堆的时间和不占用相同大小排序序列空间的优势。

目前快速排序算法主要有三种:左右指针法,挖坑法,前后指针法

下面我先给出递归操作的代码:

public static void quicksort(int[] arrs,int start,int end){

        if(start>=end)

            return;

        int mid = sort(arrs, start, end);

        quicksort(arrs, start, mid-1);

        quicksort(arrs, mid+1, end);

}

左右指针法:

大致过程是先以arrs[0]作为基准,然后让j往又从左走,i从左往右走,(注意如果以arrs[0]作为基准,那么就必须让j先执行,具体原因下面说),然后当出现arrs[j]小于基准时,arrs[i]大于基准时,交换arrs[i]和arrs[j]的值,然后继续执行。直到i,j相遇,最后交换arrs[start]与arrs[i]的值即可。

public static int sort1(int[] arrs,int start,int end){

        int i=start,j=end;

        int tmp = arrs[i];

        while(i<j){

           while (arrs[j] >= tmp && i<j)

                j--;

            while (arrs[i] <= tmp && i<j)

                i++;

            swap(arrs[i], arrs[j]);

        }

        swap(arrs[i], arrs[start]);

        return i;

}

这种方式也是我们最常见的方式,但是这种方式在测试的时候一不小心就会出现上面的错误,现在我们就说一下出错的原因:

eq:2, 6, 9, 3, 0, 1 -->2, 1, 9, 3, 0, 6-->2, 1, 0, 3, 9, 6 ------------->3, 1, 0, 2, 9, 6  

例如上面的一组数,首先以2为基准,第一次循环i指向6,j指向1,i,j交换,到第二列数;

然后进行第二次循环i指向9,j指向0,i,j交换,到第三列数;

此时如果让i先走,i遇到3停止,接着j走,但是i,j相遇,不能继续执行,i,j交换后退出循环,此时交换arrs[start]和arrs[i];到第四列数;

这时就会发现一轮交换下来的数出现了错误,而让j先走的话就不会出现这样的错误,读者可以按照上面的数和代码自己分析。

挖坑法:

大致过程也是先以arrs[0]作为基准并赋给一个临时变量tmp,然后让j往又从左走,i从左往右走,(这种方式也需要j先走),然后当出现arrs[j]小于基准时,将arrs[j]赋值给arrs[i],然后当arrs[i]大于基准,将arrs[i]赋值给arrs[j],继续执行。直到i,j相遇,最后将tmp赋值给arrs[i];

public static int sort2(int[] arrs,int start,int end){

    int i=start,j=end;

    int tmp = arrs[i];

    while(i<j){

        while (arrs[j] >= tmp && i<j)

            j--;

        arrs[i]=arrs[j];

        while (arrs[i] <= tmp && i<j)

            i++;

        arrs[j]=arrs[i];

    }

    arrs[i]=tmp;

    return i;

}

这种方式和它的名字相同,先将arrs[0]的值挖出来赋给tmp,这时只有arrs[0]一个坑,所以也需要j先走,当j退出内循环时,挖出arrs[j]的值赋给arrs[i],此时arrs[j]里面的值就会变成一个废值,接着继续执行,最后再将tmp的值赋给最后一个废坑中。

前后指针法:

大致过程也是先以arrs[0]作为基准并赋给一个临时变量tmp,利用两个指针怕q,p分别指向下一个位置和当前位置,当小于基准时,p跟在q的后面,如果出现大于基准时,q向后移动,p不动,然后当再次出现小于基准的值时且p没有跟在q的后面,p,q位置上的值交换,继续执行,最后将p指向的值与start位置上的值互换。

public static int sort3(int[] arrs,int start,int end){

    int p=start,q = start+1;

    int tmp = arrs[p];

    while(q<=end) {

        while(tmp>=arrs[q] && ++p!=q)

            swap(arrs[p], arrs[q]);

        q++;

    }

    arrs[start] = arrs[p];

    arrs[p] = tmp;

    return p;

}

这是这三种快速排序算法设计思路最奇特的方法,而且这种方法还可以用于链表的排序,个人还是比较欣赏这种算法的设计者,而且这种思路的代码设计也比较巧妙。

以上三种都是快速排序的实现方式,三种方法虽然想法上不太一致。但都达到了快速排序的要求。

缺陷:快速排序也有自身的缺点,因为快速排序对于基准值的要求比较高,如果基准值选择不当,就会导致排序效率严重降低。

eq    1,2,3,4,5,6,7,8

比如上面的这个序列如果使用快速排序并以第一个数为基准值,则排序的时间复杂度则为(n*n),而且快速排序还是一种不稳定的排序。但是这并不能掩盖它的优势,它依旧比较火的排序。

当然,网上对于基准值的选择也有一些优化的手段,具体的方法可以参考下面参照链接。

后续:很遗憾java8中的Collections.sort()方法并没有使用快速排序算法,可能是因为快速排序对于基准值难以把握。那就有点奇怪了,快速排序算法明明号称是速度第一的排序算法,为什么java8不用它,难道编写java8的人不知道吗?当然不是,值得一提的是java8中的sort方法并没有单独的利用某一个排序算法,而是充分利用了八大排序算法的优势,当排序序列小于32时使用折半查找的直接插入算法,当大于32时使用归并排序算法分割序列,序列小于32时依旧使用折半查找的直接插入算法,不过其中还有很多很多的优化策略,例如当一对序列进行归并时,归并算法需要重新分配与之长度相同的一段数组空间,很是浪费空间,但是java8先计算出不需要排序的子序列,然后只new出较短序列长度相同的数组存储临时值,与普通的归并算法比较,可以节省至少一半的空间。再其次是较短序列排序时,使用直插排序更好,所以当分隔到32长度时,选择使用直插算法。然而排序直接插入算法的时间复杂度为(n*n),而java8利用折半查找的方式让每一轮比较只进行log2N次,这样总的排序效率可以达到(n*log2N)的效果,而且任何序列都可以保证等等。总的来说,每一种排序算法都有其优势和劣势,但是如果能够充分利用各个排序算法的优势,就能够达到最佳的效果。


参照:https://blog.csdn.net/vayne_xiao/article/details/53508973

https://blog.csdn.net/qq_36528114/article/details/78667034

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

推荐阅读更多精彩内容