• 数据结构——排序算法——快速排序


    快速排序算法的基本思想是
    1.从数组中取出一个数,称之为基数(pivot
    2.遍历数组,将比基数大的数字放到它的右边,比基数小的数字放到它的左边。遍历完成后,数组被分成了左右两个区域
    3.将左右两个区域视为两个数组,重复前两个步骤,直到排序完成

    请添加图片描述

    最简单的分区算法

    分区的方式也有很多种,最简单的思路是:从 left 开始,遇到比基数大的数,就交换到数组最后,并将 right 减一,直到 left 和 right 相遇,此时数组就被分成了左右两个区域。再将基数和中间的数交换,返回中间值的下标即可。

    void exchange(vector<int> arr, int i, int j)
    {
    	int temp = arr[i];
    	arr[i] = arr[j];
    	arr[j] = temp;
    }
    
    
    void quickSort(vector<int> arr, int start, int end) 
    {
    	// 如果区域内的数字少于 2 个,退出递归
    	if (start >= end) return;
    	// 将数组分区,并获得中间值的下标
    	int middle = partition(arr, start, end);
    	// 对左边区域快速排序
    	quickSort(arr, start, middle - 1);
    	// 对右边区域快速排序
    	quickSort(arr, middle + 1, end);
    }
    
    void quickSort(vector<int> arr) {
    	quickSort(arr, 0, arr.size() - 1);
    }
    
    
    // 将 arr 从 start 到 end 分区,左边区域比基数小,右边区域比基数大,然后返回中间值的下标
    int partition(vector<int> arr, int start, int end) {
    	// 取第一个数为基数
    	int pivot = arr[start];
    	// 从第二个数开始分区
    	int left = start + 1;
    	// 右边界
    	int right = end;
    	// left、right 相遇时退出循环
    	while (left < right) {
    		// 找到第一个大于基数的位置
    		while (left < right && arr[left] <= pivot) left++;
    		// 交换这两个数,使得左边分区都小于或等于基数,右边分区大于或等于基数
    		if (left != right) {
    			exchange(arr, left, right);
    			right--;
    		}
    	}
    	// 如果 left 和 right 相等,单独比较 arr[right] 和 pivot
    	if (left == right && arr[right] > pivot) right--;
    	// 将基数和中间数交换
    	if (right != start) exchange(arr, start, right);
    	// 返回中间值的下标
    	return right;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    双指针分区算法

    除了上述的分区算法外,还有一种双指针的分区算法更为常用:从 left 开始,遇到比基数大的数,记录其下标;再从 right 往前遍历,找到第一个比基数小的数,记录其下标;然后交换这两个数。继续遍历,直到 left 和 right 相遇。然后就和刚才的算法一样了,交换基数和中间值,并返回中间值的下标。

    void exchange(vector<int> arr, int i, int j)
    {
    	int temp = arr[i];
    	arr[i] = arr[j];
    	arr[j] = temp;
    }
    
    
    // 将 arr 从 start 到 end 分区,左边区域比基数小,右边区域比基数大,然后返回中间值的下标
    int partition(vector<int> arr, int start, int end)
    {
    	// 取第一个数为基数
    	int pivot = arr[start];
    	// 从第二个数开始分区
    	int left = start + 1;
    	// 右边界
    	int right = end;
    	while (left < right) {
    		// 找到第一个大于基数的位置
    		while (left < right && arr[left] <= pivot) left++;
    		// 找到第一个小于基数的位置
    		while (left < right && arr[right] >= pivot) right--;
    		// 交换这两个数,使得左边分区都小于或等于基数,右边分区大于或等于基数
    		if (left < right) {
    			exchange(arr, left, right);
    			left++;
    			right--;
    		}
    	}
    	// 如果 left 和 right 相等,单独比较 arr[right] 和 pivot
    	if (left == right && arr[right] > pivot) right--;
    	// 将基数和轴交换
    	exchange(arr, start, right);
    	return right;
    }
    
    
    void quickSort(vector<int> arr, int start, int end)
    {
    	// 如果区域内的数字少于 2 个,退出递归
    	if (start >= end) return;
    	// 将数组分区,并获得中间值的下标
    	int middle = partition(arr, start, end);
    	// 对左边区域快速排序
    	quickSort(arr, start, middle - 1);
    	// 对右边区域快速排序
    	quickSort(arr, middle + 1, end);
    }
    
    void quickSort(vector<int> arr)
    {
    	quickSort(arr, 0, arr.size() - 1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
  • 相关阅读:
    LeetCode每日一题(1383. Maximum Performance of a Team)
    (五)算法基础——分治
    linux三剑客(grep、sed、awk)基本使用
    Java 基础高频面试题(2022年最新版)
    TS 函数 配合接口
    flask-模型(models)
    Java设计模式-行为型模式
    软件项目管理 7.1.项目进度基本概念
    ZooKeeper 8:请求处理逻辑与源码分析
    图像处理之图像的离散余弦变换
  • 原文地址:https://blog.csdn.net/weixin_43945471/article/details/132837664