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

  • Post author:
  • Post category:其他


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

一、基本思路

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

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

直到分解只剩两个数

二、递归排序代码实现

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出现在边界位置,下一次将对排序进行优化



版权声明:本文为challenglistic原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。