【数据结构】——快速排序详细说明(找基准值3种方法实现)以及非递归实现快速排序

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值

基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。

快速排序实现主框架:

//快速排序 
void QuickSort(int* arr, int left, int right)
{
	if (left >= right)
	{
		return;
	}
    //keyi即是基准值
	int keyi = _QuickSort1(arr, left, right);//实现找基准值的方法

	QuickSort(arr, left, keyi - 1);

	QuickSort(arr, keyi + 1, right);

}

Swap方法的实现 ,即交换两个数的值

void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}

hoare版本

算法思路:

1)创建左右指针,确定基准值

2)从右向左找出比基准值小的数据,从左向右找比基准值大的数据,左右指针数据交换,进入下次循环

问题1:为什么跳出循环后right位置的值⼀定不大于key? 

当 left > right 时,即right⾛到left的左侧,而left扫描过的数据均不大于key,因此right此时指向的数据⼀定不大于key

问题2:为什么left 和 right指定的数据和key值相等时也要交换?

 相等的值参与交换确实有⼀些额外消耗。实际还有各种复杂的场景,假设数组中的数据⼤量   重复时, 无法进行有效的分割排序。

int _QuickSort1(int* arr, int left, int right)
{
	int keyi = left;
	++left;
	while (left <= right)
	{
		while (left <= right && arr[right] > arr[keyi])
		{
			right--;
		}
		while (left <= right && arr[left] < arr[keyi])
		{
			left++;
		}
		if (left <= right)
		{
			Swap(&arr[left++], &arr[right--]);
		}
	}
	Swap(&arr[keyi], &arr[right]);

	return right;
}

挖坑法

思路: 创建左右指针。首先从右向左找出比基准小的数据,找到后立即放入左边坑中,当前位置变为新的"坑",然后从左向右找出比基准大的数据,找到后立即放入右边坑中,当前位置变为新的"坑",结束循环后将最开始存储的分界值放入当前的"坑"中,返回当前"坑"下标(即分界值下标)

int _QuickSort2(int* arr, int left, int right)
{
	int hole = left;//坑
	int key = arr[hole];//坑位数据

	while (left < right)
	{
		while (left < right && arr[left] >= key)
		{
			--right;
		}
		arr[hole] = arr[right];
		hole = right;

		while (left < right && arr[left] < key)
		{
			++left;
		}
		arr[hole] = arr[left];
		hole = left;
	}
	arr[hole] = arr[left];
	return hole;
}

lomuto前后指针

创建前后指针,从左往右找比基准值小的进行交换,使得小的都排在基准值的左边。

int _QuickSort3(int* arr, int left, int right)
{
	int prev = left, cur = left + 1;
	int keyi = left;
	while (cur <= right)
	{
		if (arr[cur] < arr[keyi] && ++prev != cur)
		{
			Swap(&arr[cur], &arr[prev]);
		}
		++cur;
	}
	Swap(&arr[keyi], &arr[prev]);
	return prev;
}

以上就是快速排序当中查找基准值的三种方法 

 快速排序特性总结:

1. 时间复杂度:O(nlogn) 

2. 空间复杂度:O(logn)

快速排序非递归版本,借助数据结构栈 

void QuickSortNonR(int* arr, int left, int right)
{
	ST st;
	STInit(&st);//栈的初始化
	STPush(&st, right);//压栈
	STPush(&st, left);//压栈

	while (!STEmpty(&st))
	{
		//取栈顶元素两次
		int begin = STTop(&st);
		STPop(&st);
		int end = STTop(&st);
		STPop(&st);
		//找基准值[begin,end]

		int prev = begin;
		int cur = begin + 1;
		int keyi = begin;

		while (cur <= end)
		{
			if (arr[cur] < arr[keyi] && ++prev != cur)
			{
				Swap(&arr[cur], &arr[prev]);
			}
			cur++;
		}
		Swap(&arr[keyi], &arr[prev]);

		keyi = prev;
		//根据基准值划分左右区间
		//左区间:[begin,keyi-1]
		//右区间:[keyi+1,end]

		if (keyi + 1 < end)
		{
			STPush(&st, end);
			STPush(&st,keyi + 1);
		}
		if (keyi - 1 > begin)
		{
			STPush(&st, keyi - 1);
			STPush(&st, begin);
		}
	}

	STDestroy(&st);//销毁
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值