由快速排序引起的递归问题

由快速排序引起的递归问题

发现问题

在写快速排序算法过程中,有了一个疑问,以下是调试正确可以排序的:

#include <iostream>
using namespace std;
int a[10] = {5, 9, 3, 1, 2, 8, 4, 7, 6, 10};
void quick_sort(int left, int right) {
	int base, i, j, temp;
	if (left > right) {
		return ;
	}
	base = a[left];
	i = left;
	j = right;
	while (i != j) {
		while ((a[j] >= base) && (i < j)) {
			j--;
		}
		while ((a[i] <= base) && (i < j)) {
			i++;
		}
		if (i < j) {
			temp = a[i];
			a[i] = a[j];
			a[j] = temp;
		}
	}
	a[left] = a[i];
	a[i] = base;
	
	quick_sort(left, i-1);//注意这里的 i-1 和 i--的区别,i--是改变了i的值 
	quick_sort(i+1, right);
	return ;
}
int main(void) {
	quick_sort(0, 9);
	for (i = 0; i < 10; i++) {
		cout << a[i] << " ";
	} 
	cout << endl;
	return 0;
}

在正确之后,我想到能否将以下这段代码

quick_sort(left, i-1);
quick_sort(i+1, right);

换一种写法:

quick_sort(left, --i);
quick_sort(++i, right);

结果直接挂了,问题由此产生,纳闷有啥区别为啥会挂呢?这里的形参“i-1”和“–i”,这里的区别在于 i 本身的数值第一种是没有发生变化,而第二种写法 i 本身已经变了。但是这个地方貌似也不影响最终的结果啊,当然后期通过验证,第一句这么改确实没问题,问题出在第二句上面。在此因为疑惑,就查了很多递归的样例,用一个简单的样例来说明下问题到底出在哪里。

解决问题

一个典型的递归算法解决阶乘的代码:

int Factorial(int n) {
	cout << &n << endl;
	cout << n << endl; 
	if (n == 1) {
		return 1;
	}
//	return (n * Factorial(n - 1));// ---写法 A
//	return (n * Factorial(--n));// ---写法 B
}

int main(void) {
	
//	cout << Factorial(3) << endl;
//	cout << Factorial(4) << endl;
	return 0;
}

很显然看着“写法 A”是实现了我们的阶乘想法,可是“写法 B”究竟错在哪里呢?
因此我将过程简单的分析了下,“写法 A”比较直观,没什么好多说,“写法 B”为什么如此,其实是花了好长时间才想明白的。
“写法 A”过程分析:F(3) = 3 * F(2) = 3 * (2 * F(1) ) = 3 * 2 * 1;
“写法 B”过程分析:F(3) = 2 * F(2) = 2 * (1 * F(1) ) = 2 * 1 * 1;
通过上面的样例可以看到“写法 B”的过程中由于改变了“n”的值,所以导致前面的“n”也变了,所以最终出来的结果是不对的。
当然想明白这点通过了好多种验证,最初的疑惑源头是认为形参的值是单独独立存储的,传入的只是一个值而已,两种传法的值都是一样的,因此觉得怎么传都行,调试时打印取了地址,发现确实如此,认为值这么传没有问题,但是最后发现问题是出在了这个“n”在递归过程中再次被使用了,它是和下一次递归条件密切相关的,所以就出现了问题。
为了验证,又做了一个测试,数据正确。
“写法 B”过程分析:F(4) = 3 * F(3) = 3 * (2 * F(2) ) = 3 * (2 * (1 * F(1) ) ) = 3 * 2 * 1 * 1;
至此原理已搞清楚,那么回到最初的快速排序问题上,将代码改进下,就OK了。

quick_sort(left, --i);
++i;
quick_sort(++i, right);

以上过程的解决还是耗费了一些时间的,开始把问题放到了一个算法交流群里,经过多人交流调试后才最终搞明白,在此也是把过程简单的记录下,如有什么写错的,感谢交流指导~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值