【问题标题】:Return the node itself using recursive DFS in C在 C 中使用递归 DFS 返回节点本身
【发布时间】:2021-10-16 01:16:37
【问题描述】:

我想编写一个递归搜索树,寻找具有适当数据的节点,然后返回节点本身。我需要节点本身,因为然后我将使用该节点继续构建树。我已经尝试过这个函数的许多版本,但下面的代码是我最接近的。请注意,我将一般树表示为二叉树,如 here 所述,因此我认为出于所有意图和目的,这可以视为二叉树。

struct node {
     int id;
     struct node *firstChild;
     struct node *nextSibling;
};

struct node* findNode(struct node* node, int id) {
     if (node->id == id) 
          return node;

     if (node->firstChild != NULL)
          return findNode(node->firstChild, id);

     if (node->nextSibling != NULL)
          return findNode(node->nextSibling, id);

     return node;
}

我了解此代码的问题:如果存在左(子)分支并且所需的节点不在该分支中,则它返回该分支的叶子而不是探索右分支。我知道我的代码有太多的返回语句;我尝试了其他回报较少的版本,但没有找到有效的功能。

提前致谢。

【问题讨论】:

  • 当你说“返回节点本身”时,你的意思是它按值返回(副本)节点,还是从树中删除节点并返回它?或者它返回一个指向节点的指针?
  • @Beta 或者他们可能意味着它返回节点并且喜欢......不会将它从树中删除,因为为什么会这样。而且这个函数似乎被设计成返回一个指针,而不是一个副本。
  • 好问题。我想我的意思是它应该按值返回节点。我不希望从树中删除节点;我想在节点上构建。所以我想我正在尝试在内存中找到节点的位置,以便我可以在此基础上进行构建。
  • PS 此外,给 structvariable 赋予相同的名称会使您的代码 - 以及任何尝试谈论它——非常神秘。并且给 pointer 起一个暗示非指针的名称...使用更好的名称,伙计。
  • 这就是我的理解:按值/按副本返回将返回struct node。指针返回将返回一个struct node*。后者允许您访问 您找到的节点 并直接更改结构中的数据。在 C++ 中也有按引用返回,它返回 struct node& 并且工作方式类似于按指针返回,除了代码看起来像按值/复制返回,也就是说,没有取消引用。它是语法糖。诚然,这可能有点令人困惑,但你很快就会掌握它。

标签: c algorithm binary-tree


【解决方案1】:

对于初学者来说,结构定义中有一个错字

struct node {
     int id;
     int node *firstChild;
     int node *nextSibling;
};

看来你的意思

struct node {
     int id;
     struct node *firstChild;
     struct node *nextSibling;
};

您的函数不检查当前指向节点的指针是否等于 NULL。

函数可以通过以下方式定义

struct node * findNode( struct node *node, int id ) 
{
    if ( node == NULL || node->id == id )
    {
        return node;
    }

    struct node *target = findNode( node->firstChild, id );

    if ( target == NULL )
    {
        target = findNode( node->nextSibling, id );
    }

    return target;
}

虽然在 C 中没有函数重载,但函数应该像这样声明和定义

struct node * findNode( const struct node *node, int id ) 
{
    if ( node == NULL || node->id == id )
    {
        return ( struct node * )node;
    }

    struct node *target = findNode( node->firstChild, id );

    if ( target == NULL )
    {
        target = findNode( node->nextSibling, id );
    }

    return target;
}

【讨论】:

  • 谢谢!我已经修正了我原来问题中的错字。 FWIW,我在本网站的其他地方看到了你的答案,非常感谢你也抽出时间来帮助我!
【解决方案2】:

您只需要从两个分支中提取结果并进行比较即可。

尝试以下方法:

struct node {
     int id;
     int node *firstChild;
     int node *nextSibling;
};

struct node* findNode(struct node* node, int id) {
     if (node->id == id) 
          return node;

     node *fC = findNode(node->firstChild, id);
     node *nS = findNode(node->nextSibling, id);

     //if the node is guaranteed to exist in the tree
     return (fC->id == id) ? fC : nS;

     //if the node is not guaranteed to exist in the tree
     if (fC != null && fC->id == id)
          return fC;
     if (nS != null && nS->id == id)
          return nS;
     return null;
}

【讨论】:

    【解决方案3】:

    您需要将findNode 的结果存储在一个变量(target)中。 然后检查target,如果它是NULL,这意味着它没有找到并在nextSibling 中搜索。像这样,只有在firstChild 中找不到节点时才会搜索nextSibling

    struct node* findNode(struct node* node, int id) {
         if (node == NULL) return NULL;
         if (node->id == id) return node;
         
         struct node *target = NULL;
         if (node->firstChild != NULL)
              target = findNode(node->firstChild, id);
    
         if (target == NULL && node->nextSibling != NULL)
              target = findNode(node->nextSibling, id);
    
         return target;
    }
    

    【讨论】:

    • 为什么要复制粘贴我的解决方案?
    • 我没有,我从问题的原始代码中去了。我只借了你的变量名。我们的答案之间的区别在于,我会像提问者一样检查节点的两个子节点是否为 NULL。否则可能会出现分段错误。
    • 这是我回答中代码的第一个版本,然后我更新了。
    • 你可能是对的。在回答之前我确实看过你的代码,所以我可能下意识地做了和你一样的事情。对此感到抱歉。
    猜你喜欢
    • 2010-08-12
    • 2021-09-30
    • 1970-01-01
    • 2018-12-31
    • 2020-03-01
    • 1970-01-01
    • 2017-11-19
    • 2020-09-09
    • 1970-01-01
    相关资源
    最近更新 更多