递归与分治(二 )

汉诺塔

汉诺塔来源于印度的古老传说,在世界中心贝纳勒斯(位于印度北部)的圣庙里,一块黄铜板上插着三根宝石针,印度教的主神梵天在创造世界的时候,在其中一根针上从下到上穿好了由大到小的64片金片,这就是所谓的汉诺塔;不论白天黑夜总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在根针上,小片必须在大片上面;僧侣们预言,当所有的金片都从梵天穿好的那根针上移动到另一根针上时,世界就将消失,而梵塔、庙宇和众生也将同归于尽。

汉诺塔移动规则:

1、每次只能移动1个圆盘;
2、任何时候都不允许将较大的圆盘压在较小的圆盘之上;
3、在满足移动规则1和2的前提下,可将圆盘移至A、B、C中任一塔座上。
塔座上有n个圆盘的汉诺塔问题被称为n阶汉诺塔问题;当n = 1时,只要将编号1的盘子从A移到B即可;当n > 1时,要以C位辅助,此时设法将n-1个较小的盘子从A移到C,将剩下的最大盘子从A移到B,最后设法将n-1个较小的盘子从C移到B即可;这样n个盘子的移动就可以分解为两次n-1个盘子的移动。

代码如下:

#include <iostream>

using namespace std;

void hanoi(int a, char from, char help, char to);

int main(int argc, char *argv[])
{
	int n;
	if (argc != 2)
	{
		cout << "用法:"<<argv[0]<<" 盘子总数" << endl;
		return -1;
	}
	n = atoi(argv[1]);
	hanoi(n, 'A', 'B', 'C');

	return 0;
}

void hanoi(int a, char from, char help, char to)
{
	if (a == 1)
	{
		// 递归结束的条件:只有一个盘子,直接移到 to 针
		cout << from << "--> " << to << endl;
	}
	else
	{
		// 不止一个盘子时,分解为三步走
		// 1. 称将上面 n - 1 个盘子,从 from 借助 to 移到 help 暂放
		hanoi(a-1, from, to, help);
		// 2. 将最下面的 1 个盘子从 from 移到 to
		cout << from <<"--> "<<to<<endl;
		// 3. 最后将暂放的 n - 1 个盘子从 help 借助 from 移到 to
		hanoi(a-1, help, from, to);
	}

	return;
}

执行结果:

hong@debian:/mnt/hgfs/linux/cpp/recursion$ ./main
用法:./main 盘子总数
hong@debian:/mnt/hgfs/linux/cpp/recursion$ ./main 3
A–> C
A–> B
C–> B
A–> C
B–> A
B–> C
A–> C

递归算法代码简洁、清晰、易于验证,但是时间与空间消耗较大, 原因是嵌套函数的调用,如果调用层数太深,会存在堆栈溢出的风险。
注:能不用递归就不用递归,递归都可以用迭代来代替。

分治法

分治就是“分而治之“, 分治法的基本思想就是将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相关联;通过递归方式求解子问题,然后将各个子问题的解合并成原问题的解。

分治法求数组a[1,…,n]中的最大最小值;使用分治法的思想,首先把数组分成两部分,再把这两部分的每一部分再分成两部分,一直递归下去直到每一部分或者等于两个数为止,然后比较这两个数大小,然后回弹比较直到递归的最外层,就找到最大最小值。
代码如下:

#include <iostream>

using namespace std;

int max(int num1, int num2)
{
	if (num1 > num2)
	{
		return num1;
	}
	else
	{
		return num2;
	}
}

int min(int num1, int num2)
{
	if (num1 > num2)
	{
		return num2;
	}
	else
	{
		return num1;
	}
}

void maxmin(int a[], int left, int right, int &fmax, int &fmin)
{
	int mid = 0, lmax = 0, lmin = 0, rmax = 0, rmin = 0;
	if (left == right)  // 数组只有一个元素
	{
		fmax = a[left];
		fmin = a[left];
	}
	else if (left == right-1)  // 数组只有两个元素
	{
		if(a[left] < a[right])
		{
			fmin = a[left];
			fmax = a[right];
		}
		else
		{
			fmin = a[right];
			fmax = a[left];
		}
	}
	else  // 数组两个元素以上
	{
		mid = (left + right) / 2;
		maxmin(a, left, mid, lmax, lmin);
		maxmin(a, mid+1, right, rmax, rmin);

		fmax = max(lmax, rmax);
		fmin = min(lmin, rmin);
	}
}

int main()
{
	int maxValue =0 , minValue = 0;
	int a[] = { 66, 25, 256, 64, 512, 0, 1024, 78, 99};
	maxmin(a, 0, 8, maxValue, minValue);

	cout << maxValue << "  " << minValue << endl;

	return 0;
}

执行结果:

hong@debian:/mnt/hgfs/linux/cpp/recursion$ ./main
1024 0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值