关于快速排序

来源:互联网 发布:java开发人员培训机构 编辑:程序博客网 时间:2024/04/27 16:37

今天在做leetcode的过程中用到了快排,于是自己写了一个。但是发现一些细节上的错误会导致整个程序的错误。
话不多说先贴错误代码

private void quickSort(int[] c , int low , int high){        if(c.length == 0||c.length==1||low>=high)            return;        int mid = part(c, low, high);        quickSort(c, low , mid-1);        quickSort(c , mid+1, high);    }    private int part(int[] c , int low , int high){        int i = low;        int j = high;        while(true){            while(c[++i] >= c[low]){                if(i == high)                    break;            }            while(c[j] < c[low]){                j--;                if(j == low )                    break;            }            swap(c,i,j);            if( i > j)                break;                    }        swap(c,low,j);        return j;    }    private void swap(int[] c , int i , int j){        int temp = c[i];        c[i] = c[j];        c[j] = temp;    }

测试用例c=[3,0,6,1,5,0]。首先期望输出应该是[6,5,3,1,0,0]
但是运行结果却是[0,1,3,5,0,6]。
不仅没排对,而且在大方向上也不对,本来想从打到小排序,但是整体上看却从小到大了。
那么问题出在哪儿?

让我们一步一步分析。

首先第一次调用part方法,low=0,high=5
进入循环之后,可以知道将第1个元素0和第4个元素5交换位置,得到[3,5,6,1,0,0],此时i=1,j=4。循环继续,第一个while继续寻找比3小的数,于是它来到了元素1,此时i=3,j=4。然后第二个while开始从后往前找,找一个比3大的数,于是它来到了元素6,此时i=3,j=2。接着,按照代码的指示,程序将c[3]和c[2]交换了位置。数组现在长这样

[3,5,1,6,0,0]

然后程序发现此时i=3>j=2,所以就break了,然后按照惯例,将c[low]和c[j]交换位置,得到了

[1,5,3,6,0,0]

这不科学啊!!!!!
快排的思想是在进行一轮交换之后,在轴心左边的都比轴心大,右边的都比他小才对。这第一轮我们把3作为轴心,那前面应该是5和6才对,1是什么鬼?

仔细分析一下发现,在第一个while找到一个比3小的数,和第二个while找到一个比3大的数之后,如果立即进行交换,那么如果这是这一轮的最后一次交换,那么本来位置j上的数是比3大的,被交换到了i的位置,此时位置j上的数变得比3小,此时结束循环,需要将轴心元素换到中间来,就出现了这个bug,就是把比3小的元素换到了前面去。

所以这里应该先检查i,j的大小关系,然后在进行交换。这样来确保与轴心元素交换的数字比3大。

现在我们的part方法变成了这样:

    private int part(int[] c , int low , int high){        int i = low;        int j = high;        while(true){            while(c[++i] >= c[low]){                if(i == high)                    break;            }            while(c[j] < c[low]){                j--;                if(j == low )                    break;            }            if( i > j)                break;              swap(c,i,j);                  }        swap(c,low,j);        return j;    }

修改代码之后再次运行

我的天

居然报错了,ArrayIndexOutOfBoundsException。数组越界,又是哪里脚标没搞对?

可以知道最后总是会有i=j=5的时候,当判断条件i>j并不会被满足,所以还会进行下一次循环,就会出现c[6]的情况,就出现了越界。这里需要将判断条件改为i>=j。因此整个正确的代码如下:

    private void quickSort(int[] c , int low , int high){        if(c.length == 0||c.length==1||low>=high)            return;        int mid = part(c, low, high);        quickSort(c, low , mid-1);        quickSort(c , mid+1, high);    }    private int part(int[] c , int low , int high){        int i = low;        int j = high;        while(true){            while(c[++i] >= c[low]){                if(i == high)                    break;            }            while(c[j] < c[low]){                j--;                if(j == low )                    break;            }            if( i >= j)                break;            swap(c,i,j);        }        swap(c,low,j);        return j;    }    private void swap(int[] c , int i , int j){        int temp = c[i];        c[i] = c[j];        c[j] = temp;    }

这次终于对了。。。。

0 0
原创粉丝点击