快速排序是基于分治策略的。对一个子数组A[p…r]快速排序的分治过程的三个步骤为:

分解

数组A[p…r]被划分成两个(可能空)子数组A[p…q-1]和A[q+1…r],使得A[p…q-1]中的每个元素都小于等于A[q],且小于等于A[q+1…r]中的元素。下标q也在这个划分过程中进行计算。

解决

通过递归调用快速排序,对子数组A[p…q-1]和A[q+1…r]排序。

合并

因为两个子数组就是原地排序的,将它们的合并不需要操作:整个数组A[p…r]已排序。

 

伪代码

 

算法的关键是求q的partition过程,它实现子数组A[p,..,r]的原地址重排

伪代码

 

算法选取数组的右边界A[r]作为分裂元素

讲解

 

可以看出p-i部分的数都小于等于x,i+1--j部分的数都大于j

在(b)情况:i++,交换后A[i]的值小于等于x,而原始A[i]的值本身就是大于x的交换到j的位置当然也是大于x的

最后当j==r时候,i++后也需要进行交换,虽然A[i]大于x,当时A[r]的值是等于x。快排是:左边的是小于等于x,右边的大于x

partition函数

    public int partition(int [] A,int low ,int high){
        int x = A[high];
        int i = low - 1;
        for( int j = low;j<= high - 1;j++){
            if( A[j] <= x){
                i = i + 1;
                swap(A,i,j);
            }
        }
        i = i + 1;
        swap(A,i,high);
        return i;
    }

    public void swap(int[] array,int i,int j){
        int tmp = array[i];
        array[i] = array[j];
        array[j] = tmp;
    }

求划分id的partition函数的另外一种写法

核心思想:找到左侧较大的数a,找到右侧较大的数b,a、b交换,在下一次寻找,两个指针相遇时候结束

    public int Paratition(int[] A,int left ,int right){
        if(left> right)
            return -1;
        int i = left;
        int j = right;
        int mid = A[left];
        if(i<j){
            while(i<j){
                while(i<j && mid< A[j])
                    j--;
                if(i<j){
                    A[i] = A[j];
                    i++;
                }
                while(i<j && A[i]< mid)
                    i++;
                if(i<j){
                    A[j] = A[i];
                    j--;
                }
            }
            A[i] = mid;
        }
        return i;

    }

 

快排函数

    public void quickSort(int[] A,int left,int right){
        if(left>right)
            return;
        int id = partition(A,left,right);
        quickSort(A,left,id-1);
        quickSort(A,id+1,right);

    }

 

时间复杂度

最坏情况:O(N^2)

平均情况:O(NlogN)