C++ 二叉树运算符深度复制

C++ 二叉树运算符深度复制,c++,binary-tree,deep-copy,C++,Binary Tree,Deep Copy,我正在尝试使用“=”操作符进行深度复制,但以我编写的方式,它似乎是一个浅层复制,我不明白为什么会这样。 bs2还添加了“q”,所以我可以理解它做了浅拷贝 为什么是浅拷贝,我以为是深拷贝。 如何将其更改为深度复制 here is what I tried: BSNode& BSNode::operator=(const BSNode& other) { if (this == &other) // tries to copy the object to itsel

我正在尝试使用“=”操作符进行深度复制,但以我编写的方式,它似乎是一个浅层复制,我不明白为什么会这样。 bs2还添加了“q”,所以我可以理解它做了浅拷贝 为什么是浅拷贝,我以为是深拷贝。 如何将其更改为深度复制

here is what I tried:
BSNode& BSNode::operator=(const BSNode& other) 
{
    if (this == &other) // tries to copy the object to itself
    {
        return *this;
    }
    delete _left;
    _left = other._left;
    delete _right;
    _right = other._right;

    return *this;
}
为什么是浅拷贝

因为如果您将
this
的指针成员指定为指向另一个实例所指向的同一个对象,那么您已经创建了浅拷贝

要获得树的深度副本,必须为副本创建节点。如果没有重复的节点集,则不存在树的重复(深层)副本。在赋值运算符中,没有任何位置可以创建任何节点

为什么是浅拷贝

因为如果您将
this
的指针成员指定为指向另一个实例所指向的同一个对象,那么您已经创建了浅拷贝


要获得树的深度副本,必须为副本创建节点。如果没有重复的节点集,则不存在树的重复(深层)副本。在赋值运算符中,没有任何节点可以创建。

您需要实际构造新节点,而不是(仅)删除旧节点。如果一棵树由五个节点组成,而您从未构造任何新节点,那么之后就不可能有两棵五个节点的树

您的复制赋值操作符应该表示新树的构造。在这种情况下,您可以利用一个复制构造函数(无论如何,您应该通过规则3使用该构造函数):

BSNode::BSNode(const BSNode& other) {
if(other._left){
      _left = new BSNode(*other._left);
    }
    if(other._right) {
      _right = new BSNode(*other._right);
    }
}

BSNode& BSNode::operator=(const BSNode& other) 
{
    if (this == &other) // tries to copy the object to itself
    {
        return *this;
    }
    delete _left;
    if(other._left){
      _left = new BSNode(*other._left);
    }
    delete _right;
    if(other._right) {
      _right = new BSNode(*other._right);
    }
    return *this;
}
这是一个比较,它显示了您的错误调用,它只分配了指针,与实际的对象分配相比。我假设您的构造函数是格式良好的,并且将私有成员公开,因为您没有包含我快速测试它所需的所有代码

int main(){
    // bad
    BSNode* ap = new BSNode("a");
    ap->_left = new BSNode("al");
    BSNode* bp = ap;
    bp->_left = new BSNode("bl");

    std::cout << ap->_left->_data << std::endl;

    // good
    BSNode a("a");
    a._left = new BSNode("al");
    BSNode b(a);
    b._left = new BSNode("bl");
    std::cout << a._left->_data << std::endl;
}
intmain(){
//坏的
BSNode*ap=新BSNode(“a”);
ap->_left=新BSNode(“al”);
BSNode*bp=ap;
bp->_left=新的BSNode(“bl”);

std::cout_left->_data您需要实际构建新节点,而不是(仅仅)删除旧节点。如果一棵树由五个节点组成,而您从未构建任何新节点,那么之后就不可能有两棵五个节点的树

你的复制赋值操作符应该代表一个新树的构造。在这种情况下,你可以利用复制构造函数(无论如何,你应该通过规则三使用它):

BSNode::BSNode(const BSNode& other) {
if(other._left){
      _left = new BSNode(*other._left);
    }
    if(other._right) {
      _right = new BSNode(*other._right);
    }
}

BSNode& BSNode::operator=(const BSNode& other) 
{
    if (this == &other) // tries to copy the object to itself
    {
        return *this;
    }
    delete _left;
    if(other._left){
      _left = new BSNode(*other._left);
    }
    delete _right;
    if(other._right) {
      _right = new BSNode(*other._right);
    }
    return *this;
}
与实际的对象分配相比,这里的比较显示了您的错误调用,它只分配了指针。我假设您的构造函数是格式良好的,并且将私有成员公开,因为您没有包含所有必要的代码,我无法快速测试它

int main(){
    // bad
    BSNode* ap = new BSNode("a");
    ap->_left = new BSNode("al");
    BSNode* bp = ap;
    bp->_left = new BSNode("bl");

    std::cout << ap->_left->_data << std::endl;

    // good
    BSNode a("a");
    a._left = new BSNode("al");
    BSNode b(a);
    b._left = new BSNode("bl");
    std::cout << a._left->_data << std::endl;
}
intmain(){
//坏的
BSNode*ap=新BSNode(“a”);
ap->_left=新BSNode(“al”);
BSNode*bp=ap;
bp->_left=新的BSNode(“bl”);

std::cout_left->_data在编写递归数据结构的算法时,递归地思考

首先定义您的概念:

节点a的克隆是:

  • 如果A为空,则为空;或者

  • 一个新节点,其数据是A数据的副本,左侧是A左侧节点的克隆,右侧是A右侧节点的克隆

这可以转换为帮助器方法:

BSNode*克隆节点(const BSNode*src){
if(src==nullptr)返回nullptr;
BSNode*clonedNode=新BSNode(src.data);
clonedNode.left=克隆节点(src.left);
clonedNode.right=克隆节点(src.right);
返回克隆节点;
}
现在,您可以将
运算符=
表示为:

BSNode&BSNode::operator=(常量BSNode&other)
{
如果(this==&other)//尝试将对象复制到自身
{
归还*这个;
}
此->数据=其他.data;
删除此->左;
删除此->右侧;
此->左=克隆节点(其他.左);
this->right=克隆节点(other.right);
归还*这个;
}
但是,如果左侧(或右侧)节点不是
nullptr
,则可以重用它们(而不是分配新节点)。请编写另一个帮助器方法:

void clone\u to(BSNode*&dest,const BSNode*src){
if(dest!=nullptr&&src!=nullptr){
*dest=*src;
}
否则{
删除dest;
dest=克隆节点(src);
}
}
现在您可以编写
操作符=
的最终版本了:

BSNode&BSNode::operator=(常量BSNode&other)
{
如果(this==&other)//尝试将对象复制到自身
{
归还*这个;
}
此->数据=其他.data;
克隆到(此->左,其他.左);
克隆到(此->右,其他.右);
归还*这个;
}

在为递归数据结构编写算法时,请递归思考

首先定义您的概念:

节点a的克隆是:

  • 如果A为空,则为空;或者

  • 一个新节点,其数据是A数据的副本,左侧是A左侧节点的克隆,右侧是A右侧节点的克隆

这可以转换为帮助器方法:

BSNode*克隆节点(const BSNode*src){
if(src==nullptr)返回nullptr;
BSNode*clonedNode=新BSNode(src.data);
clonedNode.left=克隆节点(src.left);
clonedNode.right=克隆节点(src.right);
返回克隆节点;
}
现在,您可以将
运算符=
表示为:

BSNode&BSNode::operator=(常量BSNode&other)
{
如果(this==&other)//尝试将对象复制到自身
{
归还*这个;
}
此->数据=其他.data;
删除此->左;
删除此->右侧;
此->左=克隆节点(其他.左);
this->right=克隆节点(other.right);
归还*这个;
}
然而,如果你离开了