二叉树复制构造函数

时间:2011-10-09 20:26:07

标签: c++

我有一个学校作业,要求我用c ++创建一个二叉树,完成所有常用的重载操作符(=,==,!=,copy,destroy等)。我目前正在努力编写复制构造函数方法。在这个赋值中,我被要求不要在operator =或copy构造函数方法中使用二叉树类的insert方法。这是二叉树类头文件:

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

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

    一般来说,我认为我的概念已经失效,但语法完全杀了我。我昨天花了整整一天的时间在这上面,我准备承认失败并寻求帮助。你们在我的代码中看到了什么错误,我该如何修复它们?

4 个答案:

答案 0 :(得分:1)

Node& copyHelper(const Node*);       // copies the tree recursively

一定是参考吗?它看起来应该是 Node *

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

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

答案 1 :(得分:1)

这一行:

Node newNode; // 4

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

您需要在节点上执行新操作。

答案 2 :(得分:0)

  1. 是的,->取消引用指针。它是*pointer.member的快捷方式。
  2. new在堆上创建对象并返回指针 - 它不会创建指针。每次在堆上创建对象时,都必须使用new
  3. Node * newNode = new Node;将指向新创建的Node的指针分配给newNode。 Node *是指向对象的指针,而不是指向指针的指针,它将是Node **。您无法执行Node newNode = new Node;,因为Node *(指针)无法转换为Node(对象)。
  4. 当您将参数作为参考时,(通常)保证参数不是。您也无需取消引用该引用,只需使用.代替->
  5. “编译器似乎认为我正在声明一个名为BinTree :: copyHelper的Node,而不是定义一个返回Node的函数。我怎样才能阻止它?” - 你是怎么得出这样的结论的?

答案 3 :(得分:0)

经过多次烦恼和拉扯头发之后,我重写了我的复制构造函数并将其编译完毕。它可能仍然存在错误,但我现在感觉好多了,部分归功于此处发布的提示。再次感谢!这是修改后的代码:

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