带返回值的递归转为非递归

带返回值的递归转为非递归与不带返回值的递归转为非递归相似。不同的地方是有个如何保存和使用返回值的问题。

以组合数计算为例。计算公式是,C(n, k) = C(n-1, k) + C(n-1, k-1)。写成递归的代码是,

c 复制代码
func cbn(n, k)
{
	if(n==k||k==0) return 1;
	else if(k==1) return n;	
	else return cbn(n-1, k)+cbn(n-1,k-1);
}

这个函数有返回值。如何改为非递归呢。分解成任务仍然是2个,C(n-1, k) 和 C(n-1, k-1)。但这里还有个求和问题。

为了便于观察,把C(n-1, k) 和 C(n-1, k-1)的返回值逐个分配在alloc数组a[]里面。ai指向a[]中空闲的下一个可以分配的索引值。并且增加一个特别的H()任务来求和,H()任务和C(n-1, k) 和 C(n-1, k-1)压入同一栈中,所以H()任务用一个不可能出现的n值,即-1,来表示 和 C()任务的区别。注意压栈的顺序是逆序即H(), C(n-1, k-1),C(n-1, k)。针对特定问题的优化这里就不讨论了:

c 复制代码
func cbn(n, k)
{
	if(k<0 || n<k) return 0;

	ai=0;
	a[ai]=0;
	n[top]=n;
	k[top]=k;
	r[top]=ai++;

	++top;
	while(top>0) {
		--top;
		n= n[top];
		k= k[top];
		r= r[top];

		if(n==-1) {
			print "r=",r, "ai=",ai;

			a[r]=a[ai-1]+a[ai-2];
			ai -= 2;
		}
		else if(n==k||k==0) a[r]=1;
		else if(k==1) a[r]=n;	
		else {
			n[top]=-1;
			k[top]=0;
			r[top++]=r;

			n[top]=n-1;
			k[top]=k-1;
			a[ai]=0;
			r[top++]=ai++;
			print "C(",n-1,",",k-1,") return @a[", ai-1,"]";

			n[top]=n-1;
			k[top]=k;
			a[ai]=0;
			r[top++]=ai++;
			print "C(",n-1,",",k,") return @a[", ai-1,"]";
		}
		for(i=0; i<ai; i++) print a[i],"\b";
		print "";
	}
	return a[0];
}

入栈的r指向给对应的组合数计算返回值分配的a[]数组位置。代码加入了适量的打印语句,以便观察每一步的运行。

以C(6,3)为例,看下运行结果:

clike 复制代码
print cbn(6,3);
C( 5 , 2 ) return @a[ 1 ]
C( 5 , 3 ) return @a[ 2 ]
0 0 0
C( 4 , 2 ) return @a[ 3 ]
C( 4 , 3 ) return @a[ 4 ]
0 0 0 0 0
C( 3 , 2 ) return @a[ 5 ]
C( 3 , 3 ) return @a[ 6 ]
0 0 0 0 0 0 0
0 0 0 0 0 0 1
C( 2 , 1 ) return @a[ 7 ]
C( 2 , 2 ) return @a[ 8 ]
0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 1 0 1
0 0 0 0 0 0 1 2 1
r= 5 ai= 9
0 0 0 0 0 3 1
r= 4 ai= 7
0 0 0 0 4
C( 3 , 1 ) return @a[ 5 ]
C( 3 , 2 ) return @a[ 6 ]
0 0 0 0 4 0 0
C( 2 , 1 ) return @a[ 7 ]
C( 2 , 2 ) return @a[ 8 ]
0 0 0 0 4 0 0 0 0
0 0 0 0 4 0 0 0 1
0 0 0 0 4 0 0 2 1
r= 6 ai= 9
0 0 0 0 4 0 3
0 0 0 0 4 3 3
r= 3 ai= 7
0 0 0 6 4
r= 2 ai= 5
0 0 10
C( 4 , 1 ) return @a[ 3 ]
C( 4 , 2 ) return @a[ 4 ]
0 0 10 0 0
C( 3 , 1 ) return @a[ 5 ]
C( 3 , 2 ) return @a[ 6 ]
0 0 10 0 0 0 0
C( 2 , 1 ) return @a[ 7 ]
C( 2 , 2 ) return @a[ 8 ]
0 0 10 0 0 0 0 0 0
0 0 10 0 0 0 0 0 1
0 0 10 0 0 0 0 2 1
r= 6 ai= 9
0 0 10 0 0 0 3
0 0 10 0 0 3 3
r= 4 ai= 7
0 0 10 0 6
0 0 10 4 6
r= 1 ai= 5
0 10 10
r= 0 ai= 3
20
20

可以看到,这个计算次序和递归解法是完全一样的。

相关推荐
木向1 小时前
leetcode92:反转链表||
数据结构·c++·算法·leetcode·链表
阿阿越1 小时前
算法每日练 -- 双指针篇(持续更新中)
数据结构·c++·算法
小爬虫程序猿4 小时前
如何利用Python解析API返回的数据结构?
数据结构·数据库·python
pianmian18 小时前
python数据结构基础(7)
数据结构·算法
ChoSeitaku10 小时前
链表交集相关算法题|AB链表公共元素生成链表C|AB链表交集存放于A|连续子序列|相交链表求交点位置(C)
数据结构·考研·链表
偷心编程11 小时前
双向链表专题
数据结构
香菜大丸11 小时前
链表的归并排序
数据结构·算法·链表
jrrz082811 小时前
LeetCode 热题100(七)【链表】(1)
数据结构·c++·算法·leetcode·链表
@小博的博客11 小时前
C++初阶学习第十弹——深入讲解vector的迭代器失效
数据结构·c++·学习
泉崎13 小时前
11.7比赛总结
数据结构·算法