修剪二叉树的代码

时间:2014-02-17 17:05:07

标签: c++ algorithm tree

我正在尝试编写一个用于删除树叶并打印其余树的代码。

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

              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;
    }

3 个答案:

答案 0 :(得分: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);
}

答案 1 :(得分:1)

if(root->left==NULL && root->right==NULL)检查两个孩子是否为NULL但元素 2 只有一个NULL所以跳过了它,而 5 永远不会被删除。右侧的元素 3 也相同。你需要对每一方进行单独检查。

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

答案 2 :(得分:1)

我必须承认,我对你在这里尝试过的算法不太了解。我想我很困惑,因为我不知道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);
 }

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

  • 使用与源
  • 相同的数据创建新节点
  • 如果源的子项存在且不是叶子,请创建该子项的副本并将其作为副本的子项。

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()分配给已删除叶子的内存。我不会把代码弄得乱七八糟,而是将它作为练习留给你。

你倾向于知道什么时候你有正确的递归代码,因为它突然看起来非常简单。