不懂就看看--快速排序和荷兰国旗问题

简介: 任取待排序元素序列中的某个元素(例如取第一个元素)作为基准,按照该元素的排序码大小,将整个元素序列划分为左右两个子序列:左侧子序列中的排序码都小于基准元素的排序码,右侧子序列中所有元素的排序码都大于或等于基准元素的排序码。基准元素则排在两个子序列中间(这也是该元素最终应安放的位置)。然后分别对这两个子序列重复实行上述方法(递归过程),直到所有元素都排在相应位置上为止。

快速排序


概念:

任取待排序元素序列中的某个元素(例如取第一个元素)作为基准,按照该元素的排序码大小,将整个元素序列划分为左右两个子序列:左侧子序列中的排序码都小于基准元素的排序码,右侧子序列中所有元素的排序码都大于或等于基准元素的排序码。基准元素则排在两个子序列中间(这也是该元素最终应安放的位置)。然后分别对这两个子序列重复实行上述方法(递归过程),直到所有元素都排在相应位置上为止。

简单来说:基于交换思想对冒泡排序的优化,也称为分区的交换排序。核心是划分,可以用递归来实现。

核心代码:

public class QuickSort {
    public static void quickSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        quickSort(arr, 0, arr.length - 1);
    }
    // arr[l...r] 排好序
    public static void quickSort(int[] arr, int L, int R) {
        if (L < R) {
            //随机取一个值
            swap(arr, L + (int) (Math.random() * (R - L + 1)), R);
            int[] p = partition(arr, L, R);
            quickSort(arr, L, p[0] - 1);// p【0】 --》等于区域的左边界  减一则为小于区域的
            quickSort(arr, p[1] + 1, R);// p【1】 --》 等于区域右边界  
        }
    }
    /**
     * 
     * 这是一个处理arr【l...r】的函数
     * 默认以arr【r】 做划分,arr【r】--》p    p《  ==p  》p
     * 返回等于区域(左边界,右边界) 所以返回一个长度为2的数组res,res【0】,res【1】
     * 
     */
    private static int[] partition(int[] arr, int L, int R) {
        int less = L - 1; //< 区右边界
        int more = R;    // >区左边界
        while (L < more) {// L表示当前数的位置,arr[R] -> 划分值
            if (arr[L] < arr[R]) { //当前数 < 划分值
                swap(arr, ++less, L++);
            } else if (arr[L] > arr[R]) {  //当前数 > 划分值
                swap(arr, --more, L);
            } else {
                L++;
            }
        }
        swap(arr, more, R);
        return new int[]{less + 1, more};
    }
    private static void swap(int[] arr, int i, int j) {
        arr[i] = arr[i] ^ arr[j];
        arr[j] = arr[i] ^ arr[j];
        arr[i] = arr[i] ^ arr[j];
    }
}


图例

荷兰国旗问题

网络异常,图片无法展示
|

给定一个数组arr和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边,要求额外空间复杂度O(1),时间复杂度O(N)

有了上面的快速排序的了解,将数组分成三块。在左边设置了一个大于等于区,这个问题可以在左边设置一个小于区,在右边设置一个大于区,不断向中间逼近,最终中间就是相等的数字,然后跟上面快排的思想基本一致,代码如下:

private static int[] partition(int[] arr, int L, int R) {
        int less = L - 1; //< 区右边界
        int more = R;    // >区左边界
        while (L < more) {// L表示当前数的位置,arr[R] -> 划分值
            if (arr[L] < arr[R]) { //当前数 < 划分值
                swap(arr, ++less, L++);
            } else if (arr[L] > arr[R]) {  //当前数 > 划分值
                swap(arr, --more, L);
            } else {
                L++;
            }
        }
        swap(arr, more, R);
        return new int[]{less + 1, more};
    }
//比较排序
    private static void swap(int[] arr, int i, int j) {
        arr[i] = arr[i] ^ arr[j];
        arr[j] = arr[i] ^ arr[j];
        arr[i] = arr[i] ^ arr[j];
    }


总结:类似C语言的双指针的移动,当小于num时,则左指针带着区域移动。

、、、

目录
相关文章
|
存储 算法 Java
【AcWing每日一题】4818. 奶牛大学
【AcWing每日一题】4818. 奶牛大学
119 0
|
人工智能 BI
《蓝桥杯每日一题》并查集·AcWing1249. 亲戚
《蓝桥杯每日一题》并查集·AcWing1249. 亲戚
58 0
LeetCode每日一题(11)——太平洋大西洋水流问题(递归,深度优先遍历实例)
大西洋太平洋水流问题 1.题目 2.示例 3.思路 理解题目 解题思路 4.代码
148 0
LeetCode每日一题(11)——太平洋大西洋水流问题(递归,深度优先遍历实例)
|
存储 机器学习/深度学习 人工智能
【蓝桥杯集训·每日一题】AcWing 1488. 最短距离
文章目录 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 三、知识风暴 Dijkstra算法
94 0
|
存储
【蓝桥杯集训·每日一题】AcWing 1079. 叶子的颜色
文章目录 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 三、知识风暴 树形DP
69 0
|
存储 移动开发 Python
【蓝桥杯集训·每日一题】AcWing 3555. 二叉树
文章目录 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 三、知识风暴 最近公共祖先
88 0
|
C++
【力扣·每日一题】807. 保持城市天际线(C++ 贪心)
【力扣·每日一题】807. 保持城市天际线(C++ 贪心)
109 0
【力扣·每日一题】807. 保持城市天际线(C++ 贪心)
|
C++
【力扣·每日一题】913. 猫和老鼠(C++ 记忆化搜索 博弈)
【力扣·每日一题】913. 猫和老鼠(C++ 记忆化搜索 博弈)
228 0
【力扣·每日一题】913. 猫和老鼠(C++ 记忆化搜索 博弈)
LeetCode每日一题——790. 多米诺和托米诺平铺
有两种形状的瓷砖:一种是 2 x 1 的多米诺形,另一种是形如 “L” 的托米诺形。两种形状都可以旋转。
131 0
LeetCode每日一题——790. 多米诺和托米诺平铺