数据结构与算法--快速排序

简介

快速排序是对冒泡排序的一种改进。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列


排序图解

从图中可以看出,每进行一次快速排序都需要指定一个值作为基准值,同时还需要左右两个指针不断的扫描,以获取右边比基准值小的数和左边比基准值大的数的下标值,然后交换该两个指针下的值,直到左右指针相遇,交换右指针跟基准值处的下标对应的值


排序原理

  1. 首先设定一个基准值和两个左右指针,通过基准值将数组分成两个部分
  2. 将大于或等于基准值的数据放到数组右边,小于基准值的数据放到数组的左边。此时左边部分中各元素都小于或等于基准值,右边部分中各元素都大于或等于基准值
  3. 然后,将左边和右边的数据进行独立的排序。对于左侧的数组数据,又取一个基准值,将该部分的数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数据做同样的处理
  4. 重复上述过程,可以看出是一个递归的步骤。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左侧和右侧两个部分的数据排完序后,整个数组的排序也就完成了

代码实现

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

    if (low >= high) {
        return;
    }

    //定义两个左右指针和一个存放基准值的变量
    int left,right,temp;

    //左右指针的值分别为数组左右两端的下标值
    left = low;
    right = high;
    //以数组第一个元素作为基准值
    temp = arr[low];

    while (left < right) {
        //从右往左扫描,找到一个比基准值小的数的下标值
        while (arr[right] >= temp && left < right) {
            right--;
        }

        //从左往右扫描,找到一个比基准值大的数的下标值
        while (arr[left] <= temp && left < right) {
            left++;
        }

        //如果满足条件则交换
        if (left < right) {
            exchange(arr,left,right);
        }
    }

    //将基准值的值放到i和j相遇处
    exchange(arr,low,right);

    //比较基准值左边的数组
    quickSort(arr,low,right - 1);
    //比较基准值右边的数组
    quickSort(arr,right + 1,high);
}

public void exchange(int[] arr, int j, int i) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

时间复杂度分析

快速排序的一次切分从两头开始交替搜索,直到left和right重合,因此,一次切分算法的时间复杂度为O(n),但整个快速排序的时间复杂度和切分的次数相关。

最优情况:每一次切分选择的基准数字刚好将当前序列等分

如果把数组的切分看做是一个树,那么上图就是它的最优情况的图示,共切分了logn次,所以,最优情况下快速排序的时间复杂度为O(nlogn)

最坏情况:每一次切分选择的基准数字是当前序列中最大数或者最小数,这使得每次切分都会有一个子组,那么总共就得切分n次,所以,最坏情况下,快速排序的时间复杂度为O(n2)

平均情况:每一次切分选择的基准数字不是最大值和最小值,也不是中值,这种情况可以用数学归纳法证明,快速排序的时间复杂度为O(nlogn)


算法稳定性

快速排序是不稳定,它不满足稳定算法的定义

算法稳定性:假设在数列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面。则这个排序算法是稳定的

posted @ 2022-07-26 22:41  伊文小哥  阅读(64)  评论(0编辑  收藏  举报