【问题标题】:Binary Tree Copy Constructor二叉树复制构造函数
【发布时间】:2011-10-09 20:26:06
【问题描述】:

我有一个学校作业,要求我用 C++ 创建一棵二叉树,并使用所有常见的重载运算符(=、==、!=、复制、销毁等)。我目前正在努力编写复制构造函数方法。在这个作业中,我被要求不要在 operator= 或复制构造函数方法中使用二叉树类的插入方法。这是二叉树类的头文件:

#ifndef BINTREE_H
#define BINTREE_H
#include <iostream>
#include "nodedata.h"
using namespace std;

class BinTree
{

public:
    BinTree();                           // constructor
    BinTree(const BinTree &);            // copy constructor, calls copyHelper
    ~BinTree();                          // destructor, calls makeEmpty
    bool insert(NodeData*);              // insert method, inserts new nodes
    bool isEmpty() const;                // true if tree is empty, otherwise false

private:
    struct Node
    {
        NodeData* data;              // pointer to data object
        Node* left;                  // left subtree pointer
        Node* right;                 // right subtree pointer
    };
    Node* root;                          // root of the tree
    Node& copyHelper(const Node*);       // copies the tree recursively
    void makeEmpty(Node*);               // deletes nodes recursively
};

#endif

这就是我目前对复制构造函数的了解:

BinTree::BinTree(const BinTree &otherTree)
{
    root = copyHelper(otherTree.root); // 1
}

Node& BinTree::copyHelper(const Node* other) // 2
{
    if(other == NULL)
    {
        return NULL; // 3
    }
    Node newNode; // 4
    if(other.data == NULL)
    {
        newNode.data = NULL; // 5
    }
    else
    {
        NodeData newNodeData(*other->data); // 6
        newNode.data = newNodeData; // 7
    }
    newNode.left = copyHelper(other.left); // 8
    newNode.right = copyHelper(other.right); // 9
    return newNode; // 10
}

这会导致各种编译错误,而我一个都不懂。这是我认为应该发生的事情: •概述:整个树将递归地从头开始复制。当每个节点返回到它上面的节点时,它应该已经包含到所有子节点(如果存在的话)的数据和链接。

  1. 由于根根据定义是指向 Node 对象的指针,因此将其分配给返回 Node 对象的函数应该没有问题。但是,编译器在这里给我一个转换错误。
  2. 以递归方式调用的 copyHelper 函数将指向原始节点之一的指针作为参数,并返回该节点的副本。
  3. 如果没有原始节点,则构建它的副本没有意义,因此返回 NULL 值。
  4. newNode 最终将成为“other”的副本。
  5. 如果“其他”没有任何 NodeData 链接到它,那么 newNode 的数据指针将改为链接到 NULL。
  6. 否则,将使用 NodeData 复制构造函数创建一个名为“newNodeData”的新 NodeData,该构造函数通过取消引用其他的 NodeData 指针来调用。
  7. newNode 的数据指针现在指向 newNodeData,它现在包含与其他 NodeData 对象相同的字符串。
  8. newNode 的左指针将指向另一个节点,该节点是通过在其他节点的左指针分配到的任何节点上调用 copyHelper 递归创建的。
  9. newNode 的右指针将指向另一个节点,该节点是通过在其他节点的右指针分配到的任何节点上调用 copyHelper 递归创建的。
  10. 只有当这个节点和它下面的所有节点都被复制并返回给它时,它才会被自己返回。

这是我现有的问题:

  • 我假设我们只需要使用 -> 而不是 .当我们取消引用指针时。这是正确的吗?
  • 我知道有时我们需要在创建对象时使用“new”语句(参见第 4 部分),但我通常只在创建指向对象的指针时才看到这样做。具体来说,我们应该在什么时候使用“new”语句?
  • 如果我将 newNode 创建为指针(IE:Node* newNode = new Node;),这不会在返回指针时导致指向指针的指针吗?这不会比让第一个指针直接指向返回的 Node 对象效率低吗?有什么技术原因我不能这样做吗?
  • 什么时候最好将指针作为参数,而不是简单地使用指针,甚至对象本身?这与这里有关吗?
  • 编译器似乎认为我在声明一个名为 BinTree::copyHelper 的节点,而不是定义一个返回节点的函数。我该如何防止这种情况发生?

总的来说,我认为我已经掌握了这些概念,但是语法完全让我丧命。昨天我真的花了一整天的时间在这上面,我准备承认失败并寻求帮助。你们在我的代码中看到了哪些错误,我该如何解决?

【问题讨论】:

    标签: c++


    【解决方案1】:

    这一行:

    Node newNode; // 4
    

    在堆栈上分配一个节点。当函数返回时,节点不再有效。它已经超出了范围。如果另一个函数调用没有重写堆栈,它可能会工作一段时间。

    你需要在节点上新建一个。

    【讨论】:

    • 啊啊啊,我怎么忘记了!?谢谢。 :)
    【解决方案2】:
    Node& copyHelper(const Node*);       // copies the tree recursively
    

    必须是参考吗?看起来应该是 Node*

    在您的copyHelper 声明中,Node 类型嵌套在BinTree 中,但您未能实现这一点。它应该是

    BinTree::Node* BinTree::copyHelper(const BinTree::Node* other)
    

    【讨论】:

    • 哦哦,不知道嵌套对象类型。谢谢!
    【解决方案3】:
    1. 是的,-&gt; 取消引用一个指针。这是*pointer.member 的快捷方式。
    2. new 在堆上创建对象并返回一个指针——它没有创建一个指针。每次在堆上创建对象时,都必须使用new
    3. Node * newNode = new Node; 将指向新创建节点的指针分配给 newNode。 Node * 是指向对象的指针,而不是指向指针的指针,即 Node **。你不能做Node newNode = new Node;,因为Node *(指针)不能转换为Node(对象)。
    4. 当您将参数作为参考时,您(通常)保证该参数不是没有的。您也不需要取消引用引用,只需使用 . 而不是 -&gt;
    5. “编译器似乎认为我在声明一个名为 BinTree::copyHelper 的节点,而不是定义一个返回节点的函数。我该如何防止这种情况发生?” - 你是怎么得出这样的结论的?

    【讨论】:

    • 知道了,感谢您的帮助。经过一番摸索,我发现我们使用指针->成员而不是 (*pointer).member,因为 .不知何故,它的优先级高于 *,而括号看起来很傻。 ;)
    【解决方案4】:

    在费了很多力气之后,我重写了我的复制构造函数并让它编译。它可能仍然存在错误,但我现在感觉好多了,这部分归功于此处发布的提示。再次感谢!这是修改后的代码:

    BinTree::BinTree(const BinTree &otherTree)
    {
        root = copyHelper(otherTree.root); // Starts recursively copying Nodes from
                                           // otherTree, starting with root Node.
    }
    
    BinTree::Node* BinTree::copyHelper(const Node* other) // Needed BinTree at beginning
                                                          // due to nested Node struct
                                                          // in BinTree class.
    {
        if(other == NULL)
        {
            return NULL; // If there's no Node to copy, return NULL.
        }
        Node* newNode = new Node;  // Dynamically allocated memory will remain after
                                   // function is no longer in scope.  Previous newNode
                                   // object here was destroyed upon function return.
    
        if(other->data == NULL) // Other is a pointer to data, which is also a pointer.
                                // -> dereferences other, and provides the item at the
                                // memory address which other normally points to.  It
                                // just so happens that since data is a pointer itself,
                                // it can still be treated as such.  I had stupidly been
                                // attempting to use . instead of ->, because I was afraid
                                // the -> would dereference data as well.  If I actually
                                // wanted to DO this, I'd have to use *other->data, which
                                // would dereference all of other->data, as if there were
                                // parenthesis around it like this: *(other->data).
                                // Misunderstanding this was the source of most of the
                                // problems with my previous implementation.
        {
            newNode->data = NULL; // The other Node doesn't contain data,
                                  // so neither will this one.
        }
        else
        {
            NodeData* newNodeData = new NodeData; // This needed to be dynamically
                                                      // allocated as well.
    
            *newNodeData = *other->data; // Copies data from other node.
            newNode->data = newNodeData;
        }
        newNode->left = copyHelper(other->left); // Recursive call to left node.
        newNode->right = copyHelper(other->right); // Recursive call to right node.
        return newNode; // Returns after child nodes have been linked to newNode.
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-28
      • 1970-01-01
      • 2021-11-25
      相关资源
      最近更新 更多