C++快速排序

hoare版本
基本思想
快速排序的hoare版本是Hoare创建这个算法时最原始的方法,也叫左右指针法,其基本思想是在数组中选出一个key值,一般是最左边的或最右边的值,然后通过左右两个指针,假设我们以最左边的值作为key值,那么就是右指针先向左走,寻找比key值小的元素,找到之后就暂停,然后左指针向右走,寻找比key值大的元素,找到之后,交换这时候左右指针指向的值,如果以最右边作为key值,就是左指针先走。
以最左边作key值为例,当左右指针相遇的时候,在把key与现在的左指针进行交换,这时就保证了在key的左边的元素都是比key小的,右边的元素都是比key大的。
下面是一组数的比较过程。

通过这一组的比较,我们就把这个数组分成了两部分,仔细观察我们还能发现这个key值现在的位置其实就是排序结束后它应该在的位置,相当于我们就排序好了key这个值,那么接下来我们就可以通过递归的方法,在对key值左边和右边的元素用相同的方法进行排序,最终就可以把整个数组排好。

以上就是hoare版本快排的基本思想,在实现排序之前,我们还有一点需要研究一下,那就是我们的最后一步是交换left与keyi的值,那么如果我们要在一组结束之后满足左侧内容比keyi值小,右侧比keyi值大,那就必须满足left与right相遇的时候left指针指向的值是小于keyi的,这一点可以保证吗?答案是可以的,下面我们来分析一下
left与right相遇只有两种情况:
(1)right遇left。
因为在比较时是right先走,所以当right先走然后遇到left时,这时的left指向的值是刚刚在上一轮与right找到的比keyi值小的值交换来的,所以它一定是小于keyi的值的,符合要求。
(2)left遇right。
left在right后走,而left寻找的是大于keyi的值,当left开始移动时说明right这时候已经找到了比keyi小的值,当left遇到right时,说明在right的左边的值没有比keyi大的值,那么这时候left指向的值就一定是小于keyi的,也符合要求。

以上的两种情况都是符合的,那么如果我们比较时让left先走,right后走,这时候就出现问题了。当right遇到left时,因为left是找大于keyi的,所以这时的left是比keyi大的,就不符合要求,所以比较时left和right的先后顺序是不可以调换的。

hoare版本的实现
我们把快排的实现分为两部分。
首先是通过一次排序排好keyi值并且返回keyi值的下标,
第二部分是我们通过递归的方法,对keyi的左边部分和右边部分进行排序

上面是第一部分的过程

这是第二部分的过程。

int PartSort1(int* a, int left, int right)
{
	int keyi = left;
	while (left < right)
	{
		while (left < right && a[right] >= a[keyi])
			right--;
		while (left < right && a[left] <= a[keyi])
			left++;
		Swap(&a[left], &a[right]);
	}
	Swap(&a[left], &a[keyi]);
	return left;
}
void QuickSort(int* a, int left, int right)
{
	if (left >= right)
		return;
	int keyi = PartSort1(a, left, right);
	QuickSort(a, left, keyi - 1);
	QuickSort(a, keyi + 1, right);
}

挖坑法
基本思想
挖坑法的思路是把keyi作为一个坑,也是使用left和right两个指针,right向向左找比keyi值小的元素,然后用这个元素去填坑,这时right就变成了一个新坑。然后再让left向右找大的,找到后让这个元素去填坑,让left的位置变成新坑,以此往复,直到left与right相遇,那么这时left与right一定会在坑处相遇,这时再把keyi的值填到坑这里就好了。
下面是挖坑法一次排序的过程

                        

每次交换完成后都像是留下一个坑一样。
其思路与hoare版本类似,先对一组数进行排序,然后再用递归的方法对整个数组进行排序。

int PartSort2(int* a, int left, int right)
{
	int key = a[left];
	while (left < right)
	{
		while (left < right && a[right] >= key)
		{
			right--;
		}
		//放到左边的坑位,右边形成新的坑
		a[left] = a[right];
		while (left < right && a[left] <= key)
		{
			left++;
		}

		a[right] = a[left];
	}
	//相遇的位置一定是坑
	a[left] = key;
	return left;
}
void QuickSort(int* a, int left, int right)
{
	if (left >= right)
		return;
	int keyi = PartSort2(a, left, right);
	QuickSort(a, left, keyi - 1);
	QuickSort(a, keyi + 1, right);
}

学习链接:https://blog.csdn.net/qq_45967533/article/details/123919118

  • 31
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值