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

快速排序算法的基本思想是

1.从数组中取出一个数,称之为基数(pivot)

2.遍历数组,将比基数大的数字放到它的右边,比基数小的数字放到它的左边。遍历完成后,数组被分成了左右两个区域

3.将左右两个区域视为两个数组,重复前两个步骤,直到排序完成

最简单的分区算法

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

cpp 复制代码
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;
}

双指针分区算法

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

cpp 复制代码
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);
}
相关推荐
GreenTea1 天前
vLLM 与 SGLang KV Cache 底层实现机制深度调研报告
前端·后端·算法
Bode_20021 天前
多资源规划(含生产调度、库存管理及产能规划)的创新优化算法
算法·调度
Logic1011 天前
C语言/数据结构位运算题解:异或XOR找出蛋糕订单中的“VIP独特口味“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
土司大王1 天前
LeetCode hot100——35.搜索插入位置:Java 二分模板、左闭右开区间与插入点分析
java·算法·leetcode
微三云生态系统架构师-彭丹1 天前
远方好物S2B2C系统架构:一级分销与保证金托管的合规技术实现
人工智能·算法
土司大王1 天前
LeetCode hot100——34.在排序数组中查找元素的第一个和最后一个位置:Java 二分模板、边界分析
java·算法·leetcode
Logic1011 天前
C语言/数据结构位运算题解:异或XOR找出飞行棋中的“独特颜色棋子“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
爱吃苹果的日记本1 天前
数据结构第三课(时间复杂度)
数据结构·学习
罗西的思考1 天前
机器人模型(WM / WAM / VLA)综合分析与对比:从「看」到「想」再到「做」
人工智能·算法·机器学习
Logic1011 天前
C语言/数据动态规划题解:翻转一次子数组后的最大子数组和——四状态DP(O(n)时间O(1)空间)
c语言·数据结构·动态规划·时间复杂度·算法题·状态机dp·最大子数组和