快速排序及其Java实现(以升序为例)

来源:互联网 发布:淘宝关键词哪里设置 编辑:程序博客网 时间:2024/06/13 22:25

与合并排序一样,快速排序也是基于分治模式的。下面是对数组A[p…r]排序的分治过程的三个步骤:
分解:数组A[p…r]被划分为两个(可能空)的子数组A[p…q-1]和A[q+1…r],其中A[p…q-1]中的元素均小于A[q],A[q+1…r]中的元素均大于A[q]。
解决:通过递归调用快速排序,对子数组A[p…q-1]和A[q+1…r]进行就地排序
合并:因为两个子数组是就地排序的,将它们合并不需要操作。

简述一下快速排序的基本思想:在数组中选一个数作为轴中值(pivot),通过不断地比较将这个轴中值放在正确的位置上(左边的数比它小,右边的数比它大)。然后再递归地在左边的子序列和右边的子序列进行同样的操作,直到子序列的长度为1.

快速排序的思想很简单,但是通过上面的介绍可以看到两个问题:
1.轴中值(pivot)怎么选?
轴中值可以随便选。
在这篇博客里介绍两种选法:a)每次都选序列最后的元素 b)随机选择
2.怎么通过比较把轴中值放在合适的位置上?
先给这个操作取个名字:PARTITION,我们要向他传递三个参数:A,p,r.
A是数组名,p是子序列第一个元素,r是子序列最后一个元素。
在各种PATITION操作的讲解中,代码是最简单直白的,下面给出PATITION操作的Java代码:

static int partition(int[] a,int p,int r) {        int temp = a[r];        int i = p-1;        int swap = 0;  //用于交换的临时变量        for(int j = p;j < r;j++) {            if(a[j]<temp) {                i++;                swap = a[i];   //交换,这里的交换用临时变量,因为可能要和自己做交换                a[i] = a[j];                a[j] = swap;            }        }        swap = a[i+1]; //交换        a[i+1] = a[r];        a[r] =swap;        return i+1;}

下面以序列[13,19,9,5,12,8,7,4,21,2,6,11]为例展示PARTITON操作(轴中值取最后一个元素):
partition操作
partition操作
partition操作
快速排序就是不断在子序列中做PARTITION操作,下面给出QuickSort的全部Java代码:

package ex;import java.util.Arrays;public class Sort {    public static void main(String args[]) {          int []a = new int[] {13,19,9,5,12,8,7,4,21,2,6,11};        quickSort(a,0,a.length-1);        System.out.println(Arrays.toString(a));    }    static int partition(int[] a,int p,int r) {        int temp = a[r];        int i = p-1;        int swap = 0;        for(int j = p;j < r;j++) {            if(a[j]<temp) {                i++;                swap = a[i];   //交换,这里的交换增加一个临时变量,因为可能要和自己做交换                a[i] = a[j];                a[j] = swap;            }        }        swap = a[i+1]; //交换        a[i+1] = a[r];        a[r] =swap;        return i+1;    }    static void quickSort(int[] a,int p,int r) {        if(p>=r)  //递归的边界条件            return;        else {            int q = partition(a,p,r);            quickSort(a,p,q-1);            quickSort(a,q+1,r);        }    }} //输出结果://[2, 4, 5, 6, 7, 8, 9, 11, 12, 13, 19, 21]

在上面代码的基础上给出快速排序的随机化版本:

package ex;import java.util.Arrays;import java.util.Random;public class Sort {    public static void main(String args[]) {          int []a = new int[] {13,19,9,5,12,8,7,4,21,2,6,11};        //quickSort(a,0,a.length-1);        randomizedQuickSort(a,0,a.length-1);        System.out.println(Arrays.toString(a));    }    static int partition(int[] a,int p,int r) {        int temp = a[r];        int i = p-1;        int swap = 0;        for(int j = p;j < r;j++) {            if(a[j]<temp) {                i++;                swap = a[i];   //交换,这里的交换用临时变量,因为可能要和自己做交换                a[i] = a[j];                a[j] = swap;            }        }        swap = a[i+1]; //交换        a[i+1] = a[r];        a[r] =swap;        return i+1;    }    static int randomizedPartition(int[] a,int p,int r) {        Random rd = new Random();        int i = rd.nextInt(r-p+1) + p;  //生成[r,p]之间的随机整数        int swap = a[i];        a[i] = a[r];   //交换        a[r] = swap;        return partition(a,p,r);    }    static void randomizedQuickSort(int[] a,int p,int r) {        if(p>=r)  //递归的边界条件            return;        else {            int q = randomizedPartition(a,p,r);            randomizedQuickSort(a,p,q-1);            randomizedQuickSort(a,q+1,r);        }    }} //输出结果://[2, 4, 5, 6, 7, 8, 9, 11, 12, 13, 19, 21]

最后,再给出另一种版本的快速排序,它用循环取代了一部分递归,一定程度上提升了算法性能:

package ex;import java.util.Arrays;public class Sort {    public static void main(String args[]) {          int []a = new int[] {13,19,9,5,12,8,7,4,21,2,6,11};        improvedQuickSort(a,0,a.length-1);        System.out.println(Arrays.toString(a));    }    static int partition(int[] a,int p,int r) {        int temp = a[r];        int i = p-1;        int swap = 0;        for(int j = p;j < r;j++) {            if(a[j]<temp) {                i++;                swap = a[i];   //交换,这里的交换用临时变量,因为可能要和自己做交换                a[i] = a[j];                a[j] = swap;            }        }        swap = a[i+1]; //交换        a[i+1] = a[r];        a[r] =swap;        return i+1;    }    static void improvedQuickSort(int[] a,int p,int r) {        while(p<r) {            int q = partition(a,p,r);            improvedQuickSort(a,p,q-1); //先对左子序列进行QuickSort            p = q + 1;                    //再对右子序列进行同样的操作        }    }} //输出结果://[2, 4, 5, 6, 7, 8, 9, 11, 12, 13, 19, 21]//在原来的快速排序中包含两个对自身的递归调用,这边只需要一个

如有错误,欢迎指正