修剪二叉树的代码

Posted

技术标签:

【中文标题】修剪二叉树的代码【英文标题】:code for pruning a binary tree 【发布时间】:2014-02-17 17:05:07 【问题描述】:

我正在尝试编写一个代码来移除树的叶子并打印树的其余部分。

在平衡树的情况下,我能够获得正确的输出。例如

              1
             / \
            2   3
           / \    \
          4  5     6

这棵树的输出必须是213(按顺序打印时)

当它是一棵不平衡的树时,我无法获得所需的输出。例如

              1
             / \
            2   3
           / \    \
          4  5     6
         / \
        7   8

我收到4 3 2 5 1 3. which is wrong.

correct answer is 4 2 1 3.(printed inorder)

谁能帮我看看我犯了什么错误?

程序的代码是

    //prune a tree


    #include<iostream>
    using namespace std;

    struct Node
        int data;
        struct Node *left;
        struct Node *right;
    ;

    struct Node *follower=NULL;
    struct Node *create_node(int item)
    
        struct Node *newNode=NULL;
        newNode= new Node;
        newNode->data=item;
        newNode->left=NULL;
        newNode->right=NULL;

        return newNode;
    

    void extract_leaves_binary_tree(struct Node *root)
    
        int na=0;
        if(root==NULL)
        return;

        if(root->left==NULL && root->right==NULL)
        
            na=1;
           
        else
        
            follower=root;
        

        if(na==1 )
               
            if(follower->left==root)
                follower->left=NULL;            
            if(follower->right==root)
                follower->right=NULL;                   
            na=0;
           
        extract_leaves_binary_tree(root->left);
        extract_leaves_binary_tree(root->right);

    


    void print(struct Node *root)
    
        if(root==NULL)
        return;

        print(root->left);
        cout<<root->data;
        print(root->right);
    

    void driver(struct Node *root)
    

        extract_leaves_binary_tree(root);

    

    int main()
    
        struct Node *root=NULL;
        root  = create_node(1);
         root->left = create_node(2);
         root->right = create_node(3);
         root->left->left = create_node(4);
         root->left->right = create_node(5);
         root->right->right = create_node(6);
         root->left->left->left = create_node(7);
        root->left->left->right = create_node(8);

        driver(root);
        cout<<"inordrer"<<endl;
        print(root);
        return 0;
    

【问题讨论】:

没有称为“C/C++”的语言。您的代码显然是 C++。从标题中删除了“c/c++”并删除了 C 标记。 @slim - 这个方法就在那里。他正在删除所有的叶子节点。 您正在使用全局变量。这是你的问题。做。不是。采用。全局变量。 我尝试在里面声明它。我遇到分段错误。 这不是使用全局的借口。没有什么是。再试一次。 【参考方案1】:

在我的脑海中,我认为做这样的事情会简单得多:

Node* internal_extract_leaves(struct Node* root)

  if(root == NULL)
    return NULL;

  if(root->left==NULL && root->right==NULL)
    return NULL;

  root->left = internal_extract_leaves(root->left);
  root->right = internal_extract_leaves(root->right);  

  return root;


void extract_leaves_binary_tree(struct Node *root)

  root = internal_extract_leaves(root);

【讨论】:

internal_extract_leaves() 末尾是否缺少return root 函数的返回类型是 Node* ,但是你在哪里返回根?【参考方案2】:

if(root-&gt;left==NULL &amp;&amp; root-&gt;right==NULL) 行检查两个孩子是否都是 NULL,但是元素 2 只有其中一个 NULL,因此它被跳过并且元素 5 永远不会被删除。右侧的元素 3 相同。您需要对每一面进行单独检查。

编辑:以上信息有误。问题是追随者是全球性的 所以你改变它,当你从左递归返回节点 2 去递归时,右侧的跟随者不再是节点 2。这意味着你不能删除它。

【讨论】:

无法在移动设备上编写代码,所以我想我至少应该指出错误。 元素 3 也有其中之一,但 6 将被删除。 因为 6 显然没有孩子,所以它被删除了。 刚刚修复了我的答案,抱歉,如果不是全局问题。我真的应该停止在外面回答问题。 我尝试在内部声明我的追随者指针,但出现分段错误。【参考方案3】:

我必须承认我无法理解您在这里尝试的算法。我想我很困惑,因为我不知道您所说的followingna 是什么意思,并且因为您将每个节点都称为root。而且,通过使用全局变量,你给了我一层我不想考虑的复杂性。

如果我不理解您的意图,那么当您在 6 个月后返回自己的代码时,您也不会理解。

它可以帮助创建具有解释性名称的函数,例如这里的isLeaf()。这是一种称为“功能分解”的技术——通过将算法分解为更小的函数来使算法更易于理解。功能分解也倾向于产生更高效的代码,因为它为优化编译器提供了更多的结构来使用。

我认为下面的代码与递归代码一样一目了然:

如果孩子存在... ...它是一片叶子,删除它 ...否则它不是叶子:递归到它
 bool isLeaf(struct Node* node) 
      // assumes we will never be passed NULL. 
      return (node->left == NULL) && (node->right == NULL);
 

 void remove_leaves(struct Node* node) 
    // assumes we will never be passed NULL. Certainly never passes itself NULL!
    if(node->left != NULL) 
       if(isLeaf(node->left)) 
          node->left = NULL;
        else 
          remove_leaves(node->left);
       
    
    if(node->right != NULL) 
       if(isLeaf(node->right)) 
          node->right = NULL;
        else 
          remove_leaves(node->right);
       
    
 

 int main() 
      struct Node *root=create_node(1);
      // create tree as before
      remove_leaves(root);
      print(root);
 

或者(由下面的 cmets 提示)您可以复制树,省略叶子:

使用与源相同的数据创建一个新节点 如果源的子节点存在且不是叶子,则创建子节点的副本并将其设为副本的子节点。
struct Node* copy_minus_leaves(struct Node *node) 
    // assume we are never passed NULL
    struct Node* copy = create_node(node->data);

    if(node->left != NULL && !isLeaf(node->left)) 
        copy->left = copy_minus_leaves(node->left);
    

    if(node->right!= NULL && !isLeaf(node->right)) 
        copy->right= copy_minus_leaves(node->right);
    

    return copy;


int main() 
    struct Node *root=create_node(1);
    // create tree as before
    struct Node *copy = copy_minus_leaves(root);
    print(copy);
 

请注意,这些算法都不会删除树的根,即使它是叶子(即树只包含一个节点)。这可能是可取的,也可能不是可取的,这取决于您使用树的目的。您需要将零节点树视为一种特殊情况。

还请注意,此代码不会free() 分配给已删除叶子的内存。我不会把代码弄得乱七八糟,而是留给你做练习。

你往往知道什么时候你的递归代码是正确的,因为它突然看起来很简单。

【讨论】:

你传递的是 NULL 吗? @slim 我没有传递 NULL 如果您没有返回任何东西。那么如何打印修剪后的树呢? 它在原地修改树。您可以编写一个函数来返回树的副本,减去叶子 -- struct Node* copy = copy_without_leaves(root); print(copy); 但这不是您的原始代码所尝试的。 我如何检查它是否正在修剪它。我可以做的一种方法是打印它。如果你不返回修剪树的根,我们将如何检查?

以上是关于修剪二叉树的代码的主要内容,如果未能解决你的问题,请参考以下文章

二叉树:修剪一棵搜索树

二叉树刷题篇(完) 二叉搜索树的修剪构造与转换

⭐算法入门⭐《二叉树 - 二叉搜索树》中等08 —— LeetCode 669. 修剪二叉搜索树

⭐算法入门⭐《二叉树 - 二叉搜索树》中等08 —— LeetCode 669. 修剪二叉搜索树

二叉树面试题刷题模板(终极版)

LeetCode 669 修剪二叉搜索树[二叉树 dfs] HERODING的LeetCode之路