我必须设计一个递归函数来应用一个赋值(我不允许使用关于河内塔的标准数学库。我偶然发现了以下代码,我认为这对于分配工作,但是不可能为(n> 30)运行它,因为它太慢了:
#include <stdio.h>
#include <stdlib.h>
int TOH(int,char,char,char);
int main()
{
int n;
printf("\nEnter number of disks:");
scanf("%d",&n);
int c = TOH(n,'A','C','B');
printf("\nTotal number of moves = %d \n ", c);
return 0;
}
int TOH(int n,char x,char y,char z)
{
int count = 0;
if(n>0){
count = TOH(n-1, x, z, y);
count++;
count += TOH(n-1, z, y, x);
}
return count;
}
在寻找速度的解决方案时,我偶然发现了这个代码,它在使用递归时立即运行。我迷失在这种速度差异来自的地方:
#include <stdio.h>
#include <stdlib.h>
float count_moves(int);
float power(int);
int main()
{
int STACKS;
printf("\nEnter numbers of disks: ");
scanf("%d", &STACKS);
float total = count_moves(STACKS);
printf("\nTotal number of moves: %.0f\n", total);
return 0;
}
float power(int multi)
{
if(!multi)
{
return 1;
}
else
{
return 2 * power(multi - 1);
}
}
float count_moves(int layers)
{
if(!layers)
{
return 0;
}
else
{
return power(layers - 1) + count_moves(layers - 1);
}
}
第二个如何能够立即在控制台中打印某些东西,而第二个需要更长的时间,我做n / STACKS的数字越大?
答案 0 :(得分:1)
首先我建议你绘制递归树。看看pegs = 30有多大。请参阅Complexity for towers of Hanoi? 它的复杂度为O(2 ^ n)。 http://www.iitk.ac.in/esc101/08Jan/lecnotes/lecture32.pdf
第二种解决方案不是以传统方式计算它。它正在打一个电话。 T(n-1)+ c = O(n ^ 2)
所以,2 ^ 30 vs 30 ^ 2。猜猜哪一个更快!
亲自看看。
为像这样的函数添加一个计数器 (制作&#39; c&#39;&#39; d&#39;全球)
float power(int multi)
{
printf("d = %d\n",d);
d++;
if(!multi)
{
return 1;
}
else
{
return 2 * power(multi - 1);
}
}
float count_moves(int layers)
{
printf("c = %d\n",c);
c++;
if(!layers)
{
return 0;
}
else
{
return power(layers - 1) + count_moves(layers - 1);
}
}
并查看他们被召唤的次数。
答案 1 :(得分:0)
忽略无意义的参数,第一个算法是count = (n > 0) ? TOH(n-1)+TOH(n-1)+1 : 0
。每次拨打TOH
都会导致另外两次拨打TOH
。其复杂度为O(2 ^ n)。每当n
加1时,费用就会翻倍。
第二个是(layers > 0) ? [something linear] + count_moves(layers - 1) : 0
。它是两个尾递归方法,但每次调用都会产生至多一个进一步的调用。但它已经这样做了n次,而且每次都做了n次&#34;所以这就是n * n。它是O(n ^ 2)。
O(2 ^ n)比O(n ^ 2)快得多。
答案 2 :(得分:0)
您的第一个版本遵循实际计算移动环的步骤顺序的方案。但是你没有明确地计算这些步骤;实际上,你的TOH
版本忽略了它的论点! (除了将它们传递给递归调用,除了将它们传递给递归调用之外,它们也会忽略它们。)
这意味着TOH
的返回值仅取决于其第一个参数n
。这也意味着使用n-1
进行的两次递归调用将返回相同的值,因此所有TOH
一次就足够了,并使用返回值两次。将if
内TOH
的正文更改为:
int tmp = TOH(n-1, x, y, z);
count = tmp + 1 + tmp;
使您的代码立即以与之前相同的答案终止。请注意,您可能会在初始n
值为31的情况下获得算术溢出。
顺便说一句,GCC级别-O3
似乎足够智能,可以在您的原始代码上自动执行此优化,而无需进行任何更改。