排序算法:快排(递归与非递归)

1.快排的思想

以这个数组为例:

快排的思想是分治策略,先找到一个基准值,给基准值找到一个合适的位置,使得基准值左边的值都小于基准值,右边的值都大于基准值。这样再分别对基准值左边和右边进行快速排序,一直到数组完全有序。既然要使得基准值左边的值都小于基准值,基准值右边的值都大于基准值,那么就避免不了数据的挪动。

让一个指针right指向数组最后一个位置,另一个指针left指向数组开始。从right开始,让数组中right的值和基准值比较,如果比基准值大,那么就right-1,一直到找到一个比基准值小的值,放到数组的left下标的位置里。接着从left开始,让数组中left的值和基准值进行比较,如果比基准值小,那么left+1;一直到找到一个比基准值大的数,放到right下标中。再重复此过程,一直到left与right相遇,就是基准值该放的位置;

 

 

 

 

这个时候left与right相遇,可以很清楚的看到,相遇位置的左边都是比12小的值,右边都是比12大的值,所以将基准值12插入到这个位置即可

 

然后还是同样的思想, 12左边进行一次快排,右边进行一次快排,数组就完全有序了。

我再展示一下12左边的快排:

 还是从right开始,找比0小的数放入arr[left]中,再从left开始找比0大的数放入arr[right]中,一直到left与right相遇。

再来看0的左边,没有元素。接着看右边,在进行快排:

 

排序完成后是这样,7的左边和右边都只有一个元素,那就是有序的,至此,12的左边以及排序完了。再接着排序12的右边。

快排的时间复杂度为O(nlogn),空间复杂度为O(logn)。由于一直存在跳跃交换,所以快排是一个不稳定的算法。

2.快排的递归实现

快排的递归实现比较简单,一直重复上述操作即可:

int Partition(int* arr, int left, int right)
{
	int tmp = arr[left];
	while (left < right)
	{
		while (left<right && arr[right]>tmp)
		{
			--right;
		}
		arr[left] = arr[right];
		while (left < right && arr[left] <= tmp)
		{
			++left;
		}
		arr[right] = arr[left];
	}
	arr[left] = tmp;
	return left;
}

void Quick(int* arr, int left, int right)
{
	if (left < right)
	{
		int par = Partition(arr, left, right);
		if (left < par - 1)
		{
			Quick(arr, left, par - 1);
		}
		if (right > par + 1)
		{
			Quick(arr, par + 1, right);
		}
	}
}

int main()
{
	int arr[] = { 56,88,14,26,99,556,47,556,324,13,5,842,1 };
	int len = sizeof(arr) / sizeof(arr[0]);
	Quick_Stack(arr, 0, len - 1);
	for (int i = 0; i < len; ++i)
	{
		cout << arr[i] << "   ";
	}
}

3.快排的非递归实现

快速排序的非递归实现,需要用到辅助工具——栈

可以将第一次基准值排完后的左边left与right和右边的left与right都放入栈中,然后边出栈边排序,排序的话又得入栈,然后又出栈又排序。这样就模拟了递归的方法,实现快排!

下面是快排非递归实现的代码:

int Partition(int* arr, int left, int right)
{
	int tmp = arr[left];
	while (left < right)
	{
		while (left<right && arr[right]>tmp)
		{
			--right;
		}
		arr[left] = arr[right];
		while (left < right && arr[left] <= tmp)
		{
			++left;
		}
		arr[right] = arr[left];
	}
	arr[left] = tmp;
	return left;
}

void Quick_Stack(int* arr, int left, int right)
{
	stack<int> st;
	if (left < right)
	{
		int par = Partition(arr, left, right);
		if (left < par - 1)
		{
			st.push(left);
			st.push(par - 1);
		}
		if (right > par + 1)
		{
			st.push(par + 1);
			st.push(right);
		}
	}
	while (!st.empty())
	{
		int l = 0;
		int r = 0;
		r = st.top();
		st.pop();
		l = st.top();
		st.pop();
		int par = Partition(arr, l, r);
		if (l < par - 1)
		{
			st.push(l);
			st.push(par - 1);
		}
		if (r > par + 1)
		{
			st.push(par + 1);
			st.push(r);
		}
	}
}

int main()
{
	int arr[] = { 56,88,14,26,99,556,47,556,324,13,5,842,1 };
	int len = sizeof(arr) / sizeof(arr[0]);
	Quick_Stack(arr, 0, len - 1);
	for (int i = 0; i < len; ++i)
	{
		cout << arr[i] << "   ";
	}
}

感谢阅读!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

g162512

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值