10 分钟看懂快速排序

思路

  1. 分区:从待排区域任选一个元素 pivot,大于它放到前面,小于它放到后面。最后会发现 pivot 所在就是有序序列中的位置。
  2. 递归:以 pivot 为分界,对左右两边进行同样的分区操作
    1. 递推公式:quick_sort(p...q)=quick_sort(quick_sort(p...r) ; quick_sort(i+1...q))
    2. 终止条件:p>=q,该分区只剩下一个元素
  3. 时间复杂度:
    1. 最好:O(nlogn),在每次 pivot 都可以将大区间一分为二
    2. 最坏: O(n^2),已经有序,每次选择最后一个元素进行分区

算法实现

重点在于分区函数,分区的实现有多种方式

public class Solution {
    public static void quickSort(int[] array) {
        quickSort(array, 0, array.length - 1);
    }

    // 递归
    public static void quickSort(int[] array, int start, int end) {
        // 终止条件
        if (start >= end) {
            return;
        }
        // 分区
        int pivot = partition(array, start, end);
        // 递归
        quickSort(array, start, pivot - 1);
        quickSort(array, pivot + 1, end);
    }

    public static void main(String[] args) {
        int[] array = new int[]{3, 5, 1, 9, 6, 2};
        quickSort(array);
        for (int i : array) {
            System.out.print(i + " ");
        }
    }
}

交换位置函数:

// 交换位置
public static void swap(int[] array, int start, int end) {
    int temp = array[start];
    array[start] = array[end];
    array[end] = temp;
}

分区方式1

  1. 类似于选择排序,
    1. 分为已处理和未处理两个区间,已处理区间内元素均小于 pivot
    2. 选择排序是从未处理区间找到最小值增加到已处理区间末尾
    3. 快速排序是从未处理区间找到比 pivot 小的值,通过交换 swop 放到已处理区间的末尾
  2. 将未处理区间的末尾作为 pivot
  3. 检查完毕将 pivot 放到已处理区间末尾,此时已处理区间元素均小于 pivot
  4. 注意 i 处于已处理区间末尾+1,把小于 pivot 的放到这里即可
  5. 使用 j 遍历所有除元素

// 分区
public static int partition(int[] array, int start, int end) {
    for (int i = start; i < end - 1; i++) {
        if (array[i] <= array[end]) {
            swap(array, start, i);
            start++;
        }
    }
    swap(array, start, end);
    return start;
}

分区方式2

  1. 分为已处理+未处理+已处理 3 个区间
  2. 把 start 作为 pivot
  3. 先从后往前与 pivot 比较,
    1. 大于等于则将 end 指针前移,end 后面的都是比 pivot 大的
    2. 小于,则与 pivot 交换位置,并且 start 向前移动一位,start 前面的都是比 pivot 小的
  4. 交换以后则从前往后与 pivot 比较
  5. 直到 start=end,则确定 pivot 的位置
  6. 优化:利用哨兵,不用交换

// 分区
public static int partition(int[] array, int start, int end) {
    int temp = array[start];
    while (start < end) {
        while (start < end && array[end] >= temp) {
            end--;
        }
        swap(array, start, end);
        start++;
        while (start < end && array[start] <= temp) {
            start++;
        }
        swap(array, start, end);
        end--;
    }
    return start;
}
// 利用哨兵
// 分区
public static int partition(int[] array, int start, int end) {
    int temp = array[start]; // 哨兵
    while (start < end) {
        while (start < end && array[end] >= temp) {
            end--;
        }
        array[start] = array[end];
        start++;
        while (start < end && array[start] <= temp) {
            start++;
        }
        array[end] = array[start];
        end--;
    }
    array[start] = temp;
    return start;
}

原创文章 249 获赞 20 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq_29150765/article/details/105195864