快速排序3(前后指针法)

一、什么是前后指针法?

前后指针法,顾名思义,就是通过控制两个指针来达到排序的目的的方法。
具体思路:先选定左边第一个为基准值key,同时设定left位置为prev,prev的后一个位置为cur,从a[cur]开始和key比较,如果a[cur]比key小,就先将prev++,再让a[cur]和a[prev]交换,然后cur++,如果a[cur]比key大,那么就不改变prev,也不用交换,只对cur++,以此类推,直到cur>right就结束,最后将a[prev]和key交换就完成了一趟快排。

二、如何用前后指针法实现快速排序?

初始化:
在这里插入图片描述
动图演示如下:
在这里插入图片描述
一趟快排之后得到的结果为:
在这里插入图片描述

三、参考代码

//三数取中
int GetMidNumi(int* a, int left, int right)
{
	int mid = (left + right) / 2;
	if (a[left] > a[mid])
	{
		if (a[mid] > a[right])
		{
			return mid;
		}
		//来到这里证明a[mid]最小,那么a[left]和a[right]
		//谁小谁就是中间的那个数
		else if (a[left] < a[right])
		{
			return left;
		}
		else
		{
			return right;
		}
	}
	else//a[left]<=a[mid]
	{
		if (a[mid] < a[right])
		{
			return mid;
		}
		//来到这里证明a[mid]最大,那么a[left]和a[right]
		//谁小谁就是中间的那个数
		else if (a[left] < a[right])
		{
			return left;
		}
		else
		{
			return right;
		}
	}
}
void InsertSort(int* a, int n)
{
	assert(a);
	int i = 0;
	int end = 0;
	int tmp = 0;

	for (i = 0; i < n - 1; i++)
	{
		end = i;
		tmp = a[end + 1];
		while (end >= 0)
		{
			if (tmp < a[end])
			{
				a[end + 1] = a[end];
				--end;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;
	}
}
int PartSort3(int* a, int left, int right)
{
	//三数取中
	int mid = GetMidNumi(a, left, right);
	//如果left就是取到的数,那么也就没有必要交换了
	if (mid != left)
	{
		Swap(&a[left], &a[mid]);
	}
	
	int keyi = left;
	int prev = left;
	int cur = prev + 1;
	while (cur <= right)//由于这里是左闭右闭区间,所以需要取等号
	{
		//这里是逻辑与操作,只有第一个条件成立,第二个条件才会参与判断
		//所以后面的++prev是在a[cur]<a[keyi]的条件下再走的,如果++prev
		//后prev==cur,证明它们的位置是一样的,也就没有必要交换了,只有等
		//prev和cur错开才需要交换
		if (a[cur] < a[keyi] && (++prev != cur))
		{
			Swap(&a[cur], &a[prev]);
		}
		//无论上面是否需要交换,cur都需要++
		cur++;
	}
	//最后prev的位置就是a[keyi]的最终的位置,交换prev和keyi对应的值
	Swap(&a[prev], &a[keyi]);

	//交换后a[prev]的值比前面的值大,比后面的值小,这里就是分界点,返回这个prev做递归的边界
	return prev;
}

void QuickSort(int* a, int left,int right)
{
	assert(a);
	//区间只有一个值或者区间不存在就不用再递归下去了
	if (left >= right)
	{
		return;
	}
	//这里进行一个小区间优化,当一个区间<=10个元素的时候
	//快排已经不再适合,因为快排是数据越多并且越乱的时候
	//才是越快的,但是数据量小的时候,快排是没有很大的优势
	// 的如果这个是一个大数组经过多次递归下来的小区间,证明
	// 这个区间接近于有序的,此时换成直接插入排序会更加的高效
	if (right - left + 1 < 10)
	{
		InsertSort(a + left, right + 1 - left);
	}
	else
	{
		//每一趟快排之后都返回keyi的位置,把区间分成
		//[left,keyi-1][keyi][keyi+1,right]三个部分
		//再对子区间的数组进行快排,直到不满足递归条件再返回
		int keyi = PartSort3(a, left, right);
		QuickSort(a, left, keyi - 1);
		QuickSort(a, keyi + 1, right);
	}

}

四、时间复杂度

快排的三个时间复杂度其实都是一样的O(N*logN),因为三种方法在思想上没有什么区别,只是在实现上略有差异。证明如下:
在这里插入图片描述

以上就是快速排序的第三个版本(前后指针法),你学会了吗?如果对你有所帮助,那就请点亮一下小心心,点点关注呗,后期还会出其它排序算法哦!

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
快速排序可以使用双指针来实现。双指针是通过两个指针i和j分别从数组的两端开始搜索,直到找到需要交换的元素。当i和j相遇时,表示搜索结束。 具体实现步骤如下: 1. 选择一个基准元素,可以是数组的第一个元素或者随机选取一个元素作为基准元素。 2. 初始化两个指针i和j,分别指向数组的起始位置和末尾位置。 3. 从右向左移动指针j,直到找到一个小于等于基准元素的元素。 4. 从左向右移动指针i,直到找到一个大于等于基准元素的元素。 5. 如果i小于等于j,则交换指针i和指针j所指向的元素。 6. 继续执行步骤3到步骤5,直到i大于j。 7. 将基准元素与指针j所指向的元素交换位置,此时基准元素的位置已经确定。 8. 对基准元素左边的子数组和右边的子数组分别进行递归排序,直到子数组的长度为1或者0。 下面是一个使用双指针实现快速排序的示例代码: ```python def quick_sort(arr, low, high): if low < high: pivot_index = partition(arr, low, high) quick_sort(arr, low, pivot_index - 1) quick_sort(arr, pivot_index + 1, high) def partition(arr, low, high): pivot = arr[low] i = low + 1 j = high while True: while i <= j and arr[i] < pivot: i += 1 while i <= j and arr[j] > pivot: j -= 1 if i <= j: arr[i], arr[j] = arr[j], arr[i] else: break arr[low], arr[j] = arr[j], arr[low] return j # 示例用 arr = [5, 2, 8, 9, 1, 3] quick_sort(arr, 0, len(arr) - 1) print(arr) # 输出:[1, 2, 3, 5, 8, 9] ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值