排序算法之快速排序(Java实现)

一、介绍及原理

​ 简单来说,快速排序就是每次选择一个基准。在遍历整个数组的过程中,将比基准小的数放到左侧,比基准大的数放到右侧。这样在一次循环过后,虽然整体依然无序,但是算法将数列分为两部分:左侧部分小于基准数而右侧部分大于基准数。之后利用分治思想分别将左侧部分与右侧部分进行快排,最终则可以得到一个完全有序的数组。

二、代码实现

 public static void QuickSort(int[] arr , int left , int right) {
     // 递归的出口必须仔细考虑清楚,否则就会陷入无穷循环从而使栈溢出   
     if (left >= right) {
            return;
        }
        int pivot = arr[left];
        int i = left;
        int j = right;
        while (i < j) {
            // 这里如果pivot 选在左侧,就要先从右侧开始遍历,反之则先从左侧开始
            while (arr[j] > pivot && i < j) {
                j--;
            }
            // 找到比基准小的数换到左侧去
            arr[i] = arr[j];
            while (arr[i] < pivot && i < j) {
                i++;
            }
            // 找到比基准大的数换到右侧去
            arr[j] = arr[i];
        }
        // 最后将基准放到中间位置
        arr[i] = pivot;
        //  递归快排左侧数列
        QuickSort(arr,left,i - 1);
        // 递归遍历右侧数列
        QuickSort(arr, i + 1, right);
    }

三、时间复杂度

在算法中有一个主定理可用来考虑算法的时间复杂度:

\[T(n) = aT(\frac{n}{b}) + O(n^{d}),(a>1,b>1,d>0) \]

\[if \ \ d <log_{b}^{a}:T(n) = O(n^{log_{b}^{a}}) \\ if \ \ d =log_{b}^{a}:T(n) = O(n^{log_{b}^{a}}log_{n}) \\ if \ \ d >log_{b}^{a}:T(n) = O(n^{d}) \]

在快速排序这个问题中:

\[T(n) = 2T(\frac{n}{2}) + O(n) \ = 4T(\frac{n}{4}) + O(n) + O(n) \]

仔细考虑排序过程,第一次将数组整个扫描了一遍,时间复杂度为O(n),扫描之后将数组分成了两个子问题:之后两个问题分为四个子问题,时间复杂度又用了O(n),正好符合上式。

其中,O(n) 是每一次分区所用的时间复杂度,将参数带入可知,快速排序的时间复杂度为O(nLogn)。

其实不利用公式来考虑时间复杂度的话:每次用O(n) 的时间复杂度将问题为了两个子问题。假设m 次过后子问题划分为1 ,那么有

\[n/2/2/.../2 = \frac{n}{2^{m}} = 1 \]

所以经过了m次迭代后,问题归一。每次的时间复杂度为O(n) = cn,那么可得快速排序的时间复杂度为:

\[cmn = clog_{2}{n}n = O(nlogn) \]

posted @ 2021-09-17 21:19  李同学的跋涉  阅读(566)  评论(0编辑  收藏  举报