算法系列—快速排序及其优化(递归)

本文详细介绍了快速排序算法的基本原理及其实现过程,并探讨了几种常见的优化方法,包括使用随机化减少最坏情况的发生概率、对小数组采用插入排序提高效率以及通过三取样切分处理含有大量重复元素的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

快速排序和归并排序是互补的,归并排序将子数组分成两个子数组分别排序,并将有序的子数组归并以将整个数组排序。而快速排序则是当两个子数组有序时整个数组也就自然有序了。

归并排序:递归调用发生在整个数组处理之前,一个数组被等分为两半。

快速排序:递归调用发生在处理整个数组之后,切分的位置取决于数组的内容。

初步实现如下:

#include <iostream>
#include <algorithm>

void sort(int A[], int lo, int hi);
int partition(int A[], int lo, int hi);

void QuickSort(int A[], int size)
{
	std::random_shuffle(A, A + size - 1);	//打乱数组
	sort(A, 0, size - 1);
}

void sort(int A[],int lo,int hi)
{
	if (lo >= hi)
		return;
	int j=partition(A, lo, hi);
	sort(A, lo, j - 1);
	sort(A, j + 1, hi);
}

int partition(int A[],int lo,int hi)
{
	//将数组切分为A[lo...i-1],A[i],A[i+1...hi]
	int i = lo, j = hi + 1; //扫描指针
	int a = A[lo];	//切分元素
	while(true)
	{
		while (A[++i] < a);	//左侧元素小于切分元素则继续比较下一个
		while (A[--j] > a);	//右侧元素大于切分元素则比较下一个
		if (i > j)	//当两个指针相遇
			break;
		std::swap(A[i], A[j]);
	}
	std::swap(A[lo], A[j]);	//扫描指针相遇后将切分元素放入正确位置
	return j;
}

int main()
{
	int A[] = { 1,4,6,4,7,4,10,50,88,2,33,56,3,345,66,67,4 };
	QuickSort(A, sizeof(A) / 4);
	for (auto a : A)
	{
		std::cout << a << " ";
	}
}

random_shuffle()打乱数组的目的:快速排序在切分不平衡时程序可能会极为低效,比如第一次从第一小的元素开始切分,第二次从第二小的元素开始切分。。在快速排序前将数组打乱就是为了避免这种情况。


算法改进:

(1)对于小数组,快速排序比插入排序慢,因此排序小数组时切换到插入排序

将sort中的语句if(hi<=lo) return; 

改为

if(hi<=lo+M)

{

//插入排序

return;

}


(2)三取样切分

实际应用中常会出现大量重复元素的数组,一个简单的方法是将数组切分为三部分,分别小于,等于和大于切分元素。

思路:从左到右遍历数组一次,维护一个指针lt使得A[lo...lt-1]中的元素都小于切分元素。一个指针gt,使得A[gt+1...hi]中的元素都大于切分元素。一个指针i使得A[lt...i-1]中的元素都等于切分元素,A[i...gt]中的元素还不确定。

比较时:

A[i]小于切分元素,将A[lt]和A[i]交换,lt和i加一

A[i]大于切分元素,将A[gt]和A[i]交换,gt减一

A[i]等于切分元素,将i加一.。


三取样切分的快速排序如下:

#include <iostream>
#include <algorithm>

void sort(int A[], int lo, int hi);

void QuickSort(int A[], int size)
{
	std::random_shuffle(A, A + size - 1);	//打乱数组
	sort(A, 0, size - 1);
}

void sort(int A[], int lo, int hi)
{
	if (lo >= hi)  //如果越界
		return;
	int lt = lo, i = lo + 1, gt = hi;
	int v = A[lo];	//切分元素
	while (i <= gt)
	{
		if (A[i] < v)
			std::swap(A[i++], A[lt++]);
		else if (A[i] == v)
			i++;
		else {
			std::swap(A[i], A[gt--]);
		}
	}
	//
	sort(A, lo, lt - 1);
	sort(A, gt + 1, hi);
}

int main()
{
	int A[] = { 1,4,6,4,7,4,10,50,88,2,33,56,3,345,66,67,4 };
	QuickSort(A, sizeof(A) / 4);
	for (auto a : A)
	{
		std::cout << a << " ";
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值