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

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

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

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

相关推荐
挖井观天11 小时前
《Java数据结构》第一讲:顺序表
数据结构
炘爚13 小时前
数据结构算法总结
数据结构·python·算法
见叶之秋14 小时前
【C++】红与黑的边界:红黑树从插入到自检
数据结构·c++·算法·面试
kiracrimson14 小时前
string 容器:从 C 字符串到会自己扩容的类
开发语言·数据结构·c++·stl
CQU_JIAKE16 小时前
10.25【A】
数据结构·算法
海清河晏11117 小时前
加油站问题
数据结构·算法·leetcode
GG.WinGel18 小时前
质数数目(蓝桥杯练习题)
java·数据结构·算法·青少年编程·蓝桥杯
敲代码的苦1319 小时前
头歌 数据结构—消防资源调度
数据结构·算法
ysu_031419 小时前
【C++ 进阶之路】(二)从内联函数到类与对象:深挖内存对齐、this 指针与三大默认成员函数
开发语言·数据结构·c++·笔记·面向对象·this
WJ.Polar19 小时前
异常、泛型、集合、Stream流
java·数据结构