C 中是否有等同于嵌套递归函数的函数?
Is there an equivalent to a nested recursive function in C?
首先,我知道C标准不支持嵌套函数。
但是,在其他语言中,定义一个将使用外部函数提供的数据的辅助递归函数通常非常有用。
这里举个例子,计算Python中N-queens problem的解数。例如,在 Lisp、Ada 或 Fortran 中很容易编写相同的代码,它们都允许某种嵌套函数。
def queens(n):
a = list(range(n))
u = [True]*(2*n - 1)
v = [True]*(2*n - 1)
m = 0
def sub(i):
nonlocal m
if i == n:
m += 1
else:
for j in range(i, n):
p = i + a[j]
q = i + n - 1 - a[j]
if u[p] and v[q]:
u[p] = v[q] = False
a[i], a[j] = a[j], a[i]
sub(i + 1)
u[p] = v[q] = True
a[i], a[j] = a[j], a[i]
sub(0)
return m
现在我的问题是:有没有办法在 C 语言中做类似的事情?我会想到两种解决方案:使用全局变量或将数据作为参数传递,但它们看起来都不太令人满意。
还有一种方法可以将其写成迭代程序,但它是clumsy:actually,我先在Fortran 77中为Rosetta Code编写了迭代解决方案,然后想整理一下这个烂摊子。 Fortran 77 没有递归函数。
对于那些想知道的人,该函数将 NxN 板管理为 [0, 1 ... N-1] 的排列,因此皇后在行和列上都是单独的。该函数正在寻找所有也是问题解决方案的排列,开始检查第一列(实际上没有什么可检查的),然后是第二列,并且仅当第一个 i
列处于有效状态时才递归调用自身配置。
当然可以。您需要模拟嵌套函数使用的特殊环境,如模块级别的 static variables。在嵌套函数之上声明它们。
为了不把事情搞砸,你把这整件事放到一个单独的模块中。
编者注:此答案从问题编辑的内容中移出,由原帖者撰写。
谢谢大家的建议。这是一个使用作为参数传递的结构的解决方案。这大致相当于 gfortran 和 gnat 在内部处理嵌套函数所做的工作。顺便说一下,参数 i
也可以在结构中传递。
内部函数被声明为静态的,以帮助编译器优化。如果它不是递归的,则可以将代码集成到外部函数(在一个简单示例中使用 GCC 进行测试),因为编译器知道不会从 "outside".
调用该函数
#include <stdio.h>
#include <stdlib.h>
struct queens_data {
int n, m, *a, *u, *v;
};
static void queens_sub(int i, struct queens_data *e) {
if(i == e->n) {
e->m++;
} else {
int p, q, j;
for(j = i; j < e->n; j++) {
p = i + e->a[j];
q = i + e->n - 1 - e->a[j];
if(e->u[p] && e->v[q]) {
int k;
e->u[p] = e->v[q] = 0;
k = e->a[i];
e->a[i] = e->a[j];
e->a[j] = k;
queens_sub(i + 1, e);
e->u[p] = e->v[q] = 1;
k = e->a[i];
e->a[i] = e->a[j];
e->a[j] = k;
}
}
}
}
int queens(int n) {
int i;
struct queens_data s;
s.n = n;
s.m = 0;
s.a = malloc((5*n - 2)*sizeof(int));
s.u = s.a + n;
s.v = s.u + 2*n - 1;
for(i = 0; i < n; i++) {
s.a[i] = i;
}
for(i = 0; i < 2*n - 1; i++) {
s.u[i] = s.v[i] = 1;
}
queens_sub(0, &s);
free(s.a);
return s.m;
}
int main() {
int n;
for(n = 1; n <= 16; n++) {
printf("%d %d\n", n, queens(n));
}
return 0;
}
首先,我知道C标准不支持嵌套函数。
但是,在其他语言中,定义一个将使用外部函数提供的数据的辅助递归函数通常非常有用。
这里举个例子,计算Python中N-queens problem的解数。例如,在 Lisp、Ada 或 Fortran 中很容易编写相同的代码,它们都允许某种嵌套函数。
def queens(n):
a = list(range(n))
u = [True]*(2*n - 1)
v = [True]*(2*n - 1)
m = 0
def sub(i):
nonlocal m
if i == n:
m += 1
else:
for j in range(i, n):
p = i + a[j]
q = i + n - 1 - a[j]
if u[p] and v[q]:
u[p] = v[q] = False
a[i], a[j] = a[j], a[i]
sub(i + 1)
u[p] = v[q] = True
a[i], a[j] = a[j], a[i]
sub(0)
return m
现在我的问题是:有没有办法在 C 语言中做类似的事情?我会想到两种解决方案:使用全局变量或将数据作为参数传递,但它们看起来都不太令人满意。
还有一种方法可以将其写成迭代程序,但它是clumsy:actually,我先在Fortran 77中为Rosetta Code编写了迭代解决方案,然后想整理一下这个烂摊子。 Fortran 77 没有递归函数。
对于那些想知道的人,该函数将 NxN 板管理为 [0, 1 ... N-1] 的排列,因此皇后在行和列上都是单独的。该函数正在寻找所有也是问题解决方案的排列,开始检查第一列(实际上没有什么可检查的),然后是第二列,并且仅当第一个 i
列处于有效状态时才递归调用自身配置。
当然可以。您需要模拟嵌套函数使用的特殊环境,如模块级别的 static variables。在嵌套函数之上声明它们。
为了不把事情搞砸,你把这整件事放到一个单独的模块中。
编者注:此答案从问题编辑的内容中移出,由原帖者撰写。
谢谢大家的建议。这是一个使用作为参数传递的结构的解决方案。这大致相当于 gfortran 和 gnat 在内部处理嵌套函数所做的工作。顺便说一下,参数 i
也可以在结构中传递。
内部函数被声明为静态的,以帮助编译器优化。如果它不是递归的,则可以将代码集成到外部函数(在一个简单示例中使用 GCC 进行测试),因为编译器知道不会从 "outside".
调用该函数#include <stdio.h>
#include <stdlib.h>
struct queens_data {
int n, m, *a, *u, *v;
};
static void queens_sub(int i, struct queens_data *e) {
if(i == e->n) {
e->m++;
} else {
int p, q, j;
for(j = i; j < e->n; j++) {
p = i + e->a[j];
q = i + e->n - 1 - e->a[j];
if(e->u[p] && e->v[q]) {
int k;
e->u[p] = e->v[q] = 0;
k = e->a[i];
e->a[i] = e->a[j];
e->a[j] = k;
queens_sub(i + 1, e);
e->u[p] = e->v[q] = 1;
k = e->a[i];
e->a[i] = e->a[j];
e->a[j] = k;
}
}
}
}
int queens(int n) {
int i;
struct queens_data s;
s.n = n;
s.m = 0;
s.a = malloc((5*n - 2)*sizeof(int));
s.u = s.a + n;
s.v = s.u + 2*n - 1;
for(i = 0; i < n; i++) {
s.a[i] = i;
}
for(i = 0; i < 2*n - 1; i++) {
s.u[i] = s.v[i] = 1;
}
queens_sub(0, &s);
free(s.a);
return s.m;
}
int main() {
int n;
for(n = 1; n <= 16; n++) {
printf("%d %d\n", n, queens(n));
}
return 0;
}