从分形的角度看递归(hanno塔)

217 篇文章 30 订阅
52 篇文章 1 订阅

1.hanno塔问题的递归分形图案,数的层数等于汉诺塔问题的层数,带颜色的表示真实的操作。

 汉诺塔实现代码:

#include <stdio.h>
#include <stdlib.h>

void hannuo(int n, char from, char to, char mid)
{
	if(n == 2)
	{
		printf("0: %c->%c.\n", from, to);
		printf("1: %c->%c.\n", from, mid);
		printf("0: %c->%c.\n", to, mid);
		printf("2: %c->%c.\n", from, to);
		printf("0: %c->%c.\n", mid, from);
		printf("1: %c->%c.\n", mid, to);
		printf("0: %c->%c.\n", from, to);
	}
	else
	{
		hannuo(n-1, from, mid, to);
		printf("%d: %c->%c.\n", n, from, to);
		hannuo(n-1, mid, to, from);
	}
}

int main(void)
{
	hannuo(3, 'A', 'B', 'C');
	return 0;
}

#include <stdio.h>
#include <stdlib.h>

static int count = 0;
void hannuo(int n, char from, char to, char mid)
{
	if(n == 2)
	{
		printf("0: %c->%c.\n", from, to);
		printf("1: %c->%c.\n", from, mid);
		printf("0: %c->%c.\n", to, mid);
		printf("2: %c->%c.\n", from, to);
		printf("0: %c->%c.\n", mid, from);
		printf("1: %c->%c.\n", mid, to);
		printf("0: %c->%c.\n", from, to);
		count += 7;
	}
	else
	{
		hannuo(n-1, from, mid, to);
		printf("%d: %c->%c.\n", n, from, to);
		count ++;
		hannuo(n-1, mid, to, from);
	}
}

int main(void)
{
	hannuo(9, 'A', 'B', 'C');
	printf("total %d.\n", count);
	return 0;
}

hanno塔的操作次数公式为:

Total = 2^{n}-1

也可以这样推导:

x_{n+1} = 2\cdot x_n + 1, \ \ x_1 = 1

\boldsymbol{x_{n+1}= 2x_n + 1 = 2(2x_{n-1}+1)+1=4x_{n-1}+2+1 = 4(2x_{n-2}+1)+2+1 =8x_{n-2}+4+2+1 = 2^{n}x_1+2^{n-1}+\cdots + 2+1=2^{n+1}-1}

2^{n}x_1+2^{n-1}+\cdots + 2+1=2^{n}+2^{n-1}+\cdots + 2+1 = 2^{n+1}-1

如果将n+1块塔看成二进制n+1 bit的二进制的话,则每个从LSB到MSB,依次需要移动

2^n, 2^{n-1}, 2^{n-2},\cdots, 2, 1

次,最高位只需要移动1次,和上面的图是吻合的。

所以

                                                        ​​​​​​​        ​​​​​​​x_n=2^n-1

n为层数,从0开始,比如,如果传入参数为hannuo(9,...),则n=10,总共需要1023步移动。

或者,修改为更加优美的形式

#include <stdio.h>
#include <stdlib.h>

static int count = 0;
void hannuo(int n, char from, char to, char mid)
{
	if(n == 0)
	{
		printf("0: %c->%c.\n", from, to);
		count += 1;
	}
	else
	{
		hannuo(n-1, from, mid, to);
		printf("%d: %c->%c.\n", n, from, to);
		count ++;
		hannuo(n-1, mid, to, from);
	}
}

int main(void)
{
	hannuo(9, 'A', 'B', 'C');
	printf("total %d.\n", count);
	return 0;
}

差异:

#include <stdio.h>
#include <stdlib.h>

static int count = 0;
void hannuo(int n, char from, char to, char mid)
{
	if(n == 0)
	{
		printf("%d: %c->%c.\n", n, from, to);
		count += 1;
	}
	else
	{
		hannuo(n-1, from, mid, to);
		printf("%d: %c->%c.\n", n, from, to);
		count ++;
		hannuo(n-1, mid, to, from);
	}
}

int main(void)
{
	hannuo(9, 'A', 'B', 'C');
	printf("total %d.\n", count);
	return 0;
}

hanno塔的最小可处理单元是2个

睡眠递归的例子

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void sleepy(int n)
{
	sleep(1);
	if(n == 0)
		printf("%s line %d.\n", __func__, __LINE__);
	else
		sleepy(n-1);

	return;
}

int main(void)
{
	sleepy(10);
	return 0;
}

尾递归改为非递归:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void sleepy(int n)
{
start:
	//printf("%s line %d, n = %d.\n", __func__, __LINE__, n); 
	sleep(1);
	//printf("%s line %d, n = %d.\n", __func__, __LINE__, n); 
	if(n == 0) {
		printf("%s line %d.\n", __func__, __LINE__);
	} else {
#if 0
		printf("%s line %d, n = %d.\n", __func__, __LINE__, n); 
		sleepy(n-1);
		printf("%s line %d, n = %d.\n", __func__, __LINE__, n); 
#else
		printf("%s line %d, n = %d.\n", __func__, __LINE__, n); 
		n --;
		//printf("%s line %d, n = %d.\n", __func__, __LINE__, n); 
		goto  start;
#endif
	}

	return;
}

int main(void)
{
	sleepy(10);
	return 0;
}

update hannuo program

#include <stdio.h>
#include <stdlib.h>

static int count = 0;
void hannuo(int n, char from, char to, char by)
{
	if(n == 0) {
		printf("step %d, move %d: %c->%c.\n", count, n, from, to);
		count += 1;
	} else {
		hannuo(n-1, from, by, to);
		printf("step %d, move %d: %c->%c.\n", count, n, from, to);
		count ++;
		hannuo(n-1, by, to, from);
	}

	return;
}

int main(void)
{
	hannuo(9, 'A', 'B', 'C');
	printf("total %d.\n", count);
	return 0;
}
$ grep "move 0:" a.log|wc -l
512
$ grep "move 1:" a.log|wc -l
256
$ grep "move 2:" a.log|wc -l
128
$ grep "move 3:" a.log|wc -l
64
$ grep "move 4:" a.log|wc -l
32
$ grep "move 5:" a.log|wc -l
16
$ grep "move 6:" a.log|wc -l
8
$ grep "move 7:" a.log|wc -l
4
$ grep "move 8:" a.log|wc -l
2
$ grep "move 9:" a.log|wc -l
1

 从LSB到MSB,每一个BIT变换的频率依次减半,比如上图,对于四个BIT的二进制数字,其BIT0变化8次,BIT1变化4,BIT2变化2,BIT3变化1,构成15个数。


结束

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

papaofdoudou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值