快速排序算法真的正确吗?-试试120,100,105,103,118 从大到小排列

快速排序算法是常用的排序算法之一,一次偶然的机会我发现快速排序算法存在一些问题,开始我以为只是我的这版教材有问题,后来才发现网上所有的快速排序算法都是这样的。

先来说说快速排序的思想吧

选取一个基准,把一个数组逻辑上分割成两个,使用递归把数组一直细分,解释的比较简单,如果还不理解这个算法就去先学习下快速排序算法,今天我主要讲的是它存在的问题

下面我写一个目前所用的从大到小的快速排序的代码(java版)

测试类

public class Test{

public static void main(String[] args){

        Scanner read=new Scanner(System.in);

        System.out.println("请输入测试5用例:");

        int[] data=new int[5];

        for(int i=0;i<5;i++)

            data[i]=read.nextInt();

        quickSort(data,0,4);

        System.out.println("排序结果:");

        for(int i=0;i<5;i++)

        System.out.print(data[i]+" ");

        System.out.println();

  }


  public static void quickSort(int[] R,int low,int high){

        int base=R[low];

        int i=low+1;

int j=high;

int temp=0;

        while(i<j){

    while((i<j)&&(R[j]<=base))

        --j;

    while((i<j)&&(R[i]>=base))

    ++i;

    if(i<j){

    temp=R[i];

    R[i]=R[j];

    R[j]=temp;

    }

}

if(R[j]>R[low]){

temp=R[low];

R[low]=R[j];

R[j]=temp;

}

if(i-low>1)

quickSort(R,low,i-1);

if(high-j>1)

quickSort(R,j+1,high);


  }

}

我们先试一组的数据 

结果没问题我们再换一组数据测试

结果并没有像我们想象的那样,老师的答复是这是一个老算法应该不会存在错误的。我决定从算法的本质入手苦思冥想了一天终于有了答案

第一轮比较我们发现base右边的数都比base小所以一直移动j,一直到 i=j=low+1时就算比较完成,我们再用j指向的数100和base指向的120比较,发现不需要替换。

后面就到了分组递归环节了,理想状态下每一组递归都会有一位数和基数base替换然后把替换位置左边(low到i+1)的分成一个组,右边(j+1到high)的分成一个组,i和j指向的那个数和基数替换我们视为有序就不参与下面的分组,

算法原本的意图就是每次用基数比较,把比基数大的分成一组,比基数小的分成一组,基数的顺序就排好了就可以固定在这个位置不用参与下面的分组。

算法每一次比较i和j指向的那个数位置固定,当出现极端情况时就会出现致命错误

当右边所有的数都比基数小时,base不需要与i和j指向的数替换位置,应该固定的位置应该是基数本身所在的位置,而不是i和j指向的数100,但是算法却错误的还是把i和j指向的那个数视为有序剔除了,不参与下面的排序,但100虽然比基数120小,但不一定会比100右边的数大,所以这里就存在问题

问题到这就清楚了,快速排序中的每一组排序都需要固定一个数的位置,并把这个数左边分成一组,右边分成一组,这种思路是正确的,但是错就错在每次被固定的这个数到底应该是i和j指向的那个位置还是基数最终所在的位置,结果很显然,因为排序就是按照基数排队,基数在数组中的顺序肯定是可以确定的,所以我们最终分组的标准应该是以基数最终所在位置为分组标准,

也就是以下两种情况下图圈圈所在的位置

也就是说当一轮比较之后发现基数的位置不需要替换时,我们应该以基数为准,将它的左右分组

解决办法也就来了,按照一般的代码编写我们就忽略上图的第一种情况,当基数位置不需要替换时怎么保证排序结果的正确

改正的代码如下

在排序方法中交换基数位置语句前插入一个判断,当基数不需要替换时就把i和j指向基数所在的位置

 if(i==low+1&&R[i]<R[low]){

               i=low;

               j=low;

    } 

public static void quickSort(int[] R,int low,int high){

        int base=R[low];

        int i=low+1;

int j=high;

int temp=0;

        while(i<j){

    while((i<j)&&(R[j]<=base))

        --j;

    while((i<j)&&(R[i]>=base))

    ++i;

    if(i<j){

    temp=R[i];

    R[i]=R[j];

    R[j]=temp;

    }

}

        if(i==low+1&&R[i]<R[low]){

  i=low;

  j=low;

}

if(R[j]>R[low]){

temp=R[low];

R[low]=R[j];

R[j]=temp;

}

if(i-low>1)

quickSort(R,low,i-1);

if(high-j>1)

quickSort(R,j+1,high);


  }

我们再测试一下刚才的那组数据,结果正确

当然还有另外一种不是很好的解决办法,就是分组的时候把i和j指向的那个位置划分到某一个组中重新参与排序,不过这样会造成资源浪费,我们只希望它在基数不需要改变位置的时候把i和j指向的位置放到数组中重新排序,当基数位置每次都需要交换时也就是我们理想的情况时就不会出现这种错误。

代码如下

把quickSort(R,j+1,high);改成了quickSort(R,j,high);

public static void quickSort(int[] R,int low,int high){

        int base=R[low];

        int i=low+1;

int j=high;

int temp=0;

        while(i<j){

    while((i<j)&&(R[j]<=base))

        --j;

    while((i<j)&&(R[i]>=base))

    ++i;

    if(i<j){

    temp=R[i];

    R[i]=R[j];

    R[j]=temp;

    }

}

if(R[j]>R[low]){

temp=R[low];

R[low]=R[j];

R[j]=temp;

}

if(i-low>1)

quickSort(R,low,i-1);

if(high-j>1)

quickSort(R,j,high);


  }

测试结果正确

小编整理了一些java进阶学习资料和面试题,需要资料的请加JAVA高阶学习Q群:701136382 这是小编创建的java高阶学习交流群,加群一起交流学习深造。群里也有小编整理的2019年最新最全的java高阶学习资料!

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

推荐阅读更多精彩内容

  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    蚁前阅读 5,173评论 0 52
  • 总结一下常见的排序算法。 排序分内排序和外排序。内排序:指在排序期间数据对象全部存放在内存的排序。外排序:指在排序...
    jiangliang阅读 1,337评论 0 1
  • 首先总结以下Java和C、C++中的一般控制台输入方式,方便以后的编程题: java键盘输入 java读文件(会自...
    androidjp阅读 2,287评论 0 16
  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 将一个记录插入到已排序好...
    依依玖玥阅读 1,250评论 0 2
  • 飞机穿越云层掠过海面 降落到这个海滨城市 那一片醉人的蓝分不清哪是海哪是天 这里有一群土著居民以种植和捕鱼为生。 ...
    Li小丫阅读 397评论 1 4