我想帮助编写一个递归搜索函数。
我有一个如下所示的数据结构:
struct node_t {
char name[16];
int num_children;
node_t** children;
};
我有很多节点在一个深树状结构中,每个节点可以有很多孩子。
要在树中的某处找到节点,我目前将根节点传递给此函数:
node_search(node_t* parent, const char* node_name) {
if(strcmp(parent->name, node_name) == 0) {
return parent;
}
else {
for(int i = 0; i < parent->num_children; ++i) {
node_t* node_found = node_search(parent->children[i], node_name);
if(strcmp(node_found->name, node_name) == 0) {
return node_found;
}
}
}
}
这似乎有效,但我观察到的两件事让我担心这不是最佳/正确的方法:
当在树中找到所需的节点时,在递归的路上,调用堆栈中的每个帧都会完成strcmp
。
当遍历树中没有所需节点的分支时,循环内的strcmp
最终会对垃圾值进行比较,这样就不会感觉非常稳固。 / p>
有人知道这种递归搜索可以用更好的方式完成吗?
答案 0 :(得分:2)
您需要在所有路径上都有一个返回值,并解决编译器应该给您的警告,这将使您理解NULL
是找不到任何内容时唯一合理的选择。
通过这种方式,您可以通过在修复此问题时消除冗余检查来显着减少代码。你这里不需要两个strcmp
。你在子弹列表中提到:“......循环中的strcmp ......” - 你已经在循环中一个strcmp
;它是在对该孩子的递归调用中完成的。再做一次是没有意义的。
node_t* node_search(node_t* parent, const char* node_name)
{
if(strcmp(parent->name, node_name) == 0)
return parent;
node_t *node_found = NULL;
for(int i = 0; !node_found && i < parent->num_children; ++i)
node_found = node_search(parent->children[i], node_name);
return node_found;
}
如果找不到该元素,那么应该返回NULL,并且在找到 节点后立即断开循环,返回链。
最后,根据此代码的位置,可能希望确保parent
在打开解除引用之前不为NULL。此代码假定在没有parent
的有效非空指针的情况下永远不会调用它。这是否是一个有效的假设(显然是在你发布的代码中)我留给你决定。
答案 1 :(得分:1)
你的函数应该在循环之外返回NULL
。
在循环内部,您应该检查返回的值是否不是NULL
,如果不是,那么内部框架已经为您进行了比较,所以只需打破循环并返回相同的值。
所以:
if (node_found != NULL)
return node_found;