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

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

以组合数计算为例。计算公式是,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

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

相关推荐
1nullptr41 分钟前
三次翻转实现数组元素的旋转
数据结构
TT哇1 小时前
【数据结构练习题】链表与LinkedList
java·数据结构·链表
A懿轩A1 小时前
C/C++ 数据结构与算法【栈和队列】 栈+队列详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·栈和队列
1 9 J2 小时前
数据结构 C/C++(实验五:图)
c语言·数据结构·c++·学习·算法
汝即来归3 小时前
选择排序和冒泡排序;MySQL架构
数据结构·算法·排序算法
aaasssdddd966 小时前
C++的封装(十四):《设计模式》这本书
数据结构·c++·设计模式
芳菲菲其弥章6 小时前
数据结构经典算法总复习(下卷)
数据结构·算法
yyyyyyykk6 小时前
数据结构--链表
数据结构·链表
我是一只来自东方的鸭.6 小时前
1. K11504 天平[Not so Mobile,UVa839]
数据结构·b树·算法
武昌库里写JAVA7 小时前
使用React Strict DOM改善React生态系统
数据结构·vue.js·spring boot·算法·课程设计