快速排序分治算法解析

快速排序分治算法解析

  • 快速排序分治算法解析
    • 声明
    • 快速排序-分治算法思路
    • 快速排序-划分算法Partition
      • 1 快速排序不稳定性
      • 2 leftIndex leq rightIndex与leftIndex rightIndex辨析
      • 3 保证pivot切分均匀
    • 快速排序-分治法递归实现代码

声明

文章均为本人技术笔记,转载请注明出处:https://segmentfault.com/u/yzwall

1.快速排序-分治算法思路


复杂度分析:由于切分算法性能不稳定,快排最差时间复杂度为 O(n2) ,平均时间复杂度为 O(nlog(n)) ,空间复杂度为 O(1)

2. 快速排序-划分算法(Partition)

需要升序排序条件下,对于一个轴点 pivot ,一次切分操作完成后保证:

pivot 的都在 pivot 左边, pivot 的都在 pivot 右边

反之,在降序排序条件下,保证

pivot 的都在 pivot 左边, pivot 的都在 pivot 右边

2.1 快速排序不稳定性

快速排序的不稳定性在于轴点 pivot 的选择上,如果 pivot 选择数组头部或者尾部,退化为冒泡排序( O(n2) ),因此 pivot 尽量选择均匀,通常进行二者取中

pivot=nums[start+(endstart)/2]

2.2 leftIndexrightIndex leftIndex<rightIndex 辨析

while (leftIndex <= rightIndex) {
    // 在左侧寻找不合法数, A[leftIndex] < pivot,保证切分均匀
    while (leftIndex <= rightIndex && A[leftIndex] < pivot) {
        ...
    }

    // 在右侧寻找不合法数, A[rightIndex] > pivot,保证切分均匀
    while (leftIndex <= rightIndex && A[rightIndex] > pivot) {
        ...
    }

    // 找到不合法数,将不合法数放入对应区间内
    if (leftIndex <= rightIndex) {
        ...
    }
    quickSort(A, start, rightIndex);
    quickSort(A, leftIndex, end);
}

leftIndexrightIndex 操作保证分治快排时,分治子数组没有重叠部分,因此如果将 leftIndexrightIndex 改成 leftIndex<rightIndex ,递归找不到出口,造成StackOverFlow

当划分操作完成后,必然有:

rightIndex<leftIndexnums[rightIndex]nums[leftIndex]

2.3 保证 pivot 切分均匀

// 在左侧寻找不合法数, A[leftIndex] < pivot,保证切分均匀
while (leftIndex <= rightIndex && A[leftIndex] < pivot) {
     leftIndex++;
}

// 在右侧寻找不合法数, A[rightIndex] > pivot,保证切分均匀
while (leftIndex <= rightIndex && A[rightIndex] > pivot) {
    rightIndex--;
}

=pivot 的数在切分过程中可以放在 pivot 左右两边:为了防止当 =pivot 在数组中大量出现时,如果严格保证 =pivot 的数在 pivot 某一侧,会造成 pivot 选择不均匀,因此必须保证 =pivot 的数字尽量在 pivot 两侧均匀分布,因此整体有序的判断条件为A[leftIndex] < pivotA[rightIndex] > pivot

2. 快速排序-分治法递归实现代码

/**
 * http://www.lintcode.com/en/problem/sort-integers-ii/
 * 快速排序一个数组(升序)
 * @author yzwall
 */
class Solution {

    public void sortIntegers2(int[] A) {
        if (A == null || A.length == 0) {
            return;
        }
        quickSort(A, 0, A.length - 1);
    }

    private void quickSort(int[]A, int start, int end) {
        // 递归出口 单元素不做排序
        if (start >= end) {
            return;
        }

        // 切分操作时间复杂度O(n),空间复杂度O(1)
        int leftIndex = start;
        int rightIndex = end;
        int pivot = A[start + (end - start) / 2];

        // leftIndex <= rightIndex, < 导致栈溢出
        while (leftIndex <= rightIndex) {
            // 在左侧寻找不合法数, A[leftIndex] < pivot,保证切分均匀
            while (leftIndex <= rightIndex && A[leftIndex] < pivot) {
                leftIndex++;
            }

            // 在右侧寻找不合法数, A[rightIndex] > pivot,保证切分均匀
            while (leftIndex <= rightIndex && A[rightIndex] > pivot) {
                rightIndex--;
            }

            // 找到不合法数,将不合法数放入对应区间内
            if (leftIndex <= rightIndex) {
                int temp = A[leftIndex];
                A[leftIndex] = A[rightIndex];
                A[rightIndex] = temp;
                // 继续查找不合法数
                leftIndex++;
                rightIndex--;
            }
        }

        /**
         * 跳出循环,leftIndex与rightIndex已互换位置
         * 分治时间复杂度O(logn), 空间复杂度O(1)
         */
        quickSort(A, start, rightIndex);
        quickSort(A, leftIndex, end);
    }
}

你可能感兴趣的:(高频面试算法题小结)