快速排序(二)——递归排序

前面已经实现了单趟排序,下面将通过递归进行第二趟、第三趟排序...来让数组有序

一、基本思路

测试数组是我们上次单趟排序的结果

在单趟排序之后,会分为左右两个区间,左右两个区间再分别进行单趟排序

直到分解只剩两个数

二、递归排序代码实现

1、单趟排序代码

下面贴上前面写的单趟排序的代码

需要注意的是,由于要根据分界点划分区间,每次单趟排序过后,要保留分界点的坐标

所以下面单趟排序的返回值 从void 改为 int

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

//单趟排序的范围是 [left , right]
int SingleSort(int* a,int left,int right)
{
	int prev, cur, key;
	prev = left;				
	cur = left + 1;
	key = a[left];		//将最左边的值作为key值

	while (cur<=right)
	{
		//若找到比key小的数,则交换
		if (a[cur] < key)
		{
			//prev++;
			//Swap(a[cur], a[prev]);
			Swap(a[cur], a[++prev]);
		}

		cur++;
	}
	Swap(a[prev], a[left]);		//将临时分界点替换为最终分界点

	return prev;
}

2、递归排序代码

注意:结束条件是 left >= right

当left = keyi 的时候

下一次递归传入的参数是 left ,keyi-1

判断的时候 left > keyi ,即区间左边界下标比右边界的下标更大,无法排序

void RecurseSort(int* a,int left,int right)
{
	//分解到最后的结束条件是left >= right
	if (left >= right)
	{
		return;
	}

	//单趟排序,选定key值,比key小的放左边,比key大的放右边,返回分界点下标keyi
	int keyi = SingleSort(a, left, right);
	//单趟排完以后,开始向左递归分解,区间范围是 [left , keyi-1]
	RecurseSort(a, left, keyi - 1);
	RecurseSort(a, keyi + 1, right);
}

 三、代码测试

int main() {
	int arr[] = { 6,1,2,7,9,3,4,5,10,8 };
	//SingleSort(arr, 0, sizeof(arr) / sizeof(arr[0]) - 1);
	RecurseSort(arr, 0, sizeof(arr) / sizeof(arr[0]) - 1);

	for (size_t i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}

四、时间复杂度

根据 “二、基本思路” 可以将流程图简单化

(1)最理想的情况

   每次单趟排序排完,key值都在数组的中间

  这个时候的逻辑结构十分接近完全二叉树

  —> 树的深度:log N

  —> 每一层cur移动的总次数:N(每一层都是N个数不变)

所以时间复杂度最好为:O(N*log N)

 (2)最糟的情况

最糟的情况就是每一趟的分界点都在最左侧

此时 cur的移动次数 = N-1 + N-2 + ... + 1 = N*(N-1)/2

所以时间复杂度为:O(N^2)

为了尽量避免key出现在边界位置,下一次将对排序进行优化

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值