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

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

以组合数计算为例。计算公式是,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 小时前
排序算法(五)--归并排序
数据结构·算法·排序算法
搬砖的小码农_Sky7 小时前
C语言:数组
c语言·数据结构
飞滕人生TYF9 小时前
m个数 生成n个数的所有组合 详解
java·递归
先鱼鲨生9 小时前
数据结构——栈、队列
数据结构
一念之坤9 小时前
零基础学Python之数据结构 -- 01篇
数据结构·python
IT 青年9 小时前
数据结构 (1)基本概念和术语
数据结构·算法
熬夜学编程的小王9 小时前
【初阶数据结构篇】双向链表的实现(赋源码)
数据结构·c++·链表·双向链表
liujjjiyun10 小时前
小R的随机播放顺序
数据结构·c++·算法
Reese_Cool12 小时前
【数据结构与算法】排序
java·c语言·开发语言·数据结构·c++·算法·排序算法
djk888812 小时前
.net将List<实体1>的数据转到List<实体2>
数据结构·list·.net