作者前言

大家好,我是阿濠,今篇内容跟大家分享的是排序算法之快速排序,很高兴分享到segmentfault与大家一起学习交流,初次见面请大家多多关照,一起学习进步.

一、快速排序的介绍

基本介绍

快速排序(Quicksort) 是对冒泡排序的一种改进

基本思想

1.通过一趟排序要排序的数据`分割成独立的两部分`
2.一部分所有数据比另外一部分所有数据都要小
3.按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列

快速排序示意图

图片.png

二、通过应用示例认识快速排序

有一群小牛,考试成绩分别是{-9,78,0,23,-567,70},请从小到大进行快速排序,以中间为基准

图片.png

我们首先先让{-9,78,0,23,-567,70}变成{-9,-567,0,23,78,70}

static int temp=0;
public static void quickSort(int[] arr,int left, int right) {

    int l = left; //左下标

    int r = right; //右下标

    //pivot中轴值  (左下标+由下标)/2
    int pivot = arr[(left  + right) / 2];

    //while循环的目的是让
    //比pivpt小的值放在左边
    //比pivpt大的值放在右边
    while( l < r){

        //从pivot左边进行寻找,若arr[l] > pivot
        //则找到比pivot的值大,这时退出循环
        while( arr[l] < pivot ){
            l += 1;//否则 ++ 后移继续寻找
        }

        //从pivot右边进行寻找,若arr[r] < pivot
        //则找到比pivot的值小,这时退出循环
        while( arr[r] > pivot ){
            r -= 1;//否则 -- 前移继续寻找
        }
        
        //如果l >= r 说明pivot的左右两值已是按照思路
        //左边是小于pivot的值
        //右边是大于pivot的值
        if( l >= r){
            break;
        }
        
        //此时左边已找到比pivot大的值
        //此时右边已找到比pivot小的值
        //将它们进行交换
        temp=arr[l];
        arr[l]=arr[r];
        arr[r]=temp;

        //若交换完出现与pivot的值则直接后移即可
        //比如说有一数组:{2,8,4,4,7,5}
        //进行交换后则是:{2,4,4,8,7,5}
        
        //若不进行后移或者前移
        //则{2,8,4,4,7,5}交换完后:{2,4,4,8,7,5}
        //此时进入第二次while循环 l=1 r=3
        //arr[l]<pivot 不满足
        //arr[r]>pivot 不满足
        //又进行交换:{2,4,4,8,7,5} 变成{2,8,4,4,7,5} 死循环
        
        //如果交换完后,发现这个arr[1] == pivot值相等r--,前移
        if(arr[1] == pivot) {
            r -= 1;
        }
        
        //如果交换完后,发现这个arr[r] == pivot值相等1++,后移
        if(arr[r] == pivot) {
            l += 1;
        }
        
       
    }
}

运行结果如下:
原数组:[-9, 78, 0, 23, -567, 70]
进行第一次分解后:[-9, -567, 0, 23, 78, 70]

接下来将进行左递归右递归继续分解下去

static int temp=0;
public static void quickSort(int[] arr,int left, int right) {

    int l = left; //左下标

    int r = right; //右下标

    //pivot中轴值  (左下标+由下标)/2
    int pivot = arr[(left  + right) / 2];

    //while循环的目的是让
    //比pivpt小的值放在左边
    //比pivpt大的值放在右边
    while( l < r){

        //从pivot左边进行寻找,若arr[l] > pivot
        //则找到比pivot的值大,这时退出循环
        while( arr[l] < pivot ){
            l += 1;//否则 ++ 后移继续寻找
        }

        //从pivot右边进行寻找,若arr[r] < pivot
        //则找到比pivot的值小,这时退出循环
        while( arr[r] > pivot ){
            r -= 1;//否则 -- 前移继续寻找
        }
        
        //如果l >= r 说明pivot的左右两值已是按照思路
        //左边是小于pivot的值
        //右边是大于pivot的值
        if( l >= r){
            break;
        }
        
        //此时左边已找到比pivot大的值
        //此时右边已找到比pivot小的值
        //将它们进行交换
        temp=arr[l];
        arr[l]=arr[r];
        arr[r]=temp;

        //若交换完出现与pivot的值则直接后移即可
        //比如说有一数组:{2,8,4,4,7,5}
        //进行交换后则是:{2,4,4,8,7,5}
        
        //若不进行后移或者前移,则{2,8,4,4,7,5}交换完后:{2,4,4,8,7,5}
        //此时进入第二次while循环 l=1 r=3
        //arr[l]<pivot 不满足
        //arr[r]>pivot 不满足
        //又进行交换:{2,4,4,8,7,5} 变成{2,8,4,4,7,5} 死循环
        
        //如果交换完后,发现这个arr[1] == pivot值相等r--,前移
        if(arr[1] == pivot) {
            r -= 1;
        }
        
        //如果交换完后,发现这个arr[r] == pivot值相等1++,后移
        if(arr[r] == pivot) {
            l += 1;
        }
        
    }
    
    //如果l == r 必须l++ r-- 为什么呢?
    //因为进行第一次分解后[-9, -567, 0, 23, 78, 70] l=1 r=3
    //此时在进入while 循环 arr[l]<pivot 满足 ++ l=2
    //此时在进入while 循环 arr[r]>pivot 满足 -- r=2
    //按图所示这时左递归是组应该是[-9,-567] 对应的是0-1
    //中间基数为 0 对应下标是 2
    //按图所示这时右递归是组应该是[23,78,70]  对应的是3-5
    //所以此时l=2 r=2 则是不对的所以必须需要l++ r--
    if( l == r){
        l++;
        r--;
    }

    //进行左递归
    if( left < r ){
        //左递归是组应该是[-9,-567] 对应的是0-1
       quickSort(arr,left,r);
    }

    //进行右递归
    if(right > l){
        //右递归是组应该是[23,78,70]  对应的是3-5
       quickSort(arr,l,right);
    }
}

运行结果如下:
原数组:[-9, 78, 0, 23, -567, 70]
进行第一次分解后:[-9, -567, 0, 23, 78, 70]
左递归与右递归进行继续分解后:[-567, -9, 0, 23, 70, 78]

三、复杂度分析

最好的情况

我们发现使用中间数作为基数,这是最好的情况,时间复杂度:O(nlogn)

最复杂的情况

图片.png

这其实和冒泡排序类似,意味着快速排序在最坏情况时间复杂度:O(n^2)

空间复杂度

和归并排序不同,快速排序在每次递归的过程中只需要开辟O(1)的存储空间完成交换操作实现直接对数组的修改;而递归次数为logn,所以它的整体空间复杂度完全取决于压堆栈的次数

所以空间复杂度是O(logn)


28640
116 声望25 粉丝

心有多大,舞台就有多大