排序(6)——快速排序算法之挖坑版&前后指针版

目录

挖坑版

基本思路

代码实现

 注意点

前后指针版

基本思路

代码实现

注意点


由于hoare版本的快速排序有很多坑和需要注意的地方,就会导致代码写起来不容易,这里我们给出两种不同的单趟排序思路:挖坑版&前后指针版

挖坑版

基本思路

先将第一个数记作key,然后把它当作一个坑位。右边先走找小,找到后填补到坑位上,然后该位置变成新的坑位。接着左边走找大,找到后再将该数填到坑位上,该位置变成新坑位。如此循环往复,直到二人相遇,再把key填补到相遇点。

如下为图解

代码实现

  • 注意:holei是下标!!
// 挖坑法
int PartSort2(int* a, int begin, int end)
{
	int midi = GetMidi(a, begin, end);
	Swap(&a[midi], &a[begin]);

	int key = a[begin];
	int holei = begin;
	while (begin < end)
	{
		// 右边找小,填到左边的坑
		while (begin < end && a[end] >= key)
		{
			--end;
		}

		a[holei] = a[end];
		holei = end;

		// 左边找大,填到右边的坑
		while (begin < end && a[begin] <= key)
		{
			++begin;
		}

		a[holei] = a[begin];
		holei = begin;
	}

	a[holei] = key;
	return holei;
}

 注意点

  • holei是下标
  • key是最左边的值,则right先走
  • key是最右边的值,则left先走
  • 要记得将坑位转移
  • 时间复杂度:O(N)

该方法本质上还是hoare的思想,在性能上并没有比hoare好,但是更好理解

前后指针版

基本思路

首元素为key,设置两个指针cur和prev,prev指向第一个元素,cur指向它的下一个元素。

  • cur找大比key值大的值,++cur
  • cur找到比key值小的值,++prev,交换prev和cur位置的值,++cur

关于交换:

  • prev可能会和cur指向同一个值,这个时候他们两个还没有分开。
  • 当二者拉开距离,prev就会和远处的cur交换值了。此时的prev就是比key要大的值,因为cur在之前已经过滤掉了这些数,从而达到小值换到前面,大值换到后面的效果。

如下图解 

我们可以看出,这就类似于推箱子,遇到比key小的值了后,一直将7和9往后退,将小的那个值往前推。

代码实现

//前后指针
int PartSort3(int* a, int begin, int end)
{
	int midi = GetMidi(a, begin, end);
	Swap(&a[midi], &a[begin]);
	int keyi = begin;

	int prev = begin;
	int cur = prev + 1;
	while (cur <= end)
	{
		if (a[cur] < a[keyi] && ++prev != cur)
			Swap(&a[prev], &a[cur]);

		++cur;
	}

	Swap(&a[prev], &a[keyi]);
	keyi = prev;
	return keyi;
}

注意点

  • 如果++prev==cur的话,那就是自己和自己交换,那么在这里是没有必要的,我们可以直接让cur++即可,所以我们将它归并到else里。
  • keyi是下标
  • 注意结束条件,cur<=end要加等号,因为当cur==end的时候,还要判断。只有当它越界的时候才跳出循环。
  • 时间复杂度:O(N)

这三种方法单趟排序出来的结果都不一样!!注意区分。

  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值