【发布时间】:2017-06-24 06:21:46
【问题描述】:
我正在用函数式语言 (ML) 编写几个递归函数,其中一些函数需要保持计数。我不允许使用尾递归或辅助函数。我应该如何计数?
例如,如果一个问题要求我删除字符串的第 n 个元素,我怎么知道递归函数在删除该元素之前已经被调用了 n 次?
【问题讨论】:
我正在用函数式语言 (ML) 编写几个递归函数,其中一些函数需要保持计数。我不允许使用尾递归或辅助函数。我应该如何计数?
例如,如果一个问题要求我删除字符串的第 n 个元素,我怎么知道递归函数在删除该元素之前已经被调用了 n 次?
【问题讨论】:
您可以将计数作为参数传递。我不了解 ML,但在 C 风格的语言中,它是这样完成的:
void processTreeNode(Node* node, int count) {
foreach(Node* child in node->children) {
processTreeNode( child, count + 1 );
}
}
第一次调用的值通常为0 或1:
Node* root = ...
processTreeNode( root, 1 );
请注意,上面的示例实际上计算的是 depth 而不是迭代次数。
如果你想计算函数实际被调用的次数,你可以使用全局状态的值(一个坏主意)或通过引用传递的线程局部值:
void processTreeNode(Node* node, int* count) {
(*count)++;
foreach(Node* child in node->children) {
processTreeNode( child, count );
}
}
第一个调用负责创建值和引用:
Node* root = ...
int count = 0;
processTreeNode( root, &count );
这可以概括为传递给所有函数调用的算法“上下文”对象——如果它是通过引用传递的,那么这可以避免不必要的值复制和堆栈空间分配,并且在没有其他条件的情况下是线程安全的线程可以访问它:
class MyAlgorithmContext {
int foo;
string bar;
}
Node* root = ...
MyAlgorithmContext context;
context.foo = 123;
processTreeNode( root, &context );
【讨论】: