简单的 C-ish 方式:我们添加一个递归克隆节点的函数
#include <iostream>
struct node{
int number = 0;
node* right_child = nullptr; // nullptr safer than NULL
node* left_child = nullptr;
};
node * clone(const node * src){
if (src) { // there is a node. Copy it.
return new node{src->number,
clone(src->right_child), // clone right
clone(src->left_child)}; // clone left
}
else { // no node. Nothing to do and end the branch
return nullptr;
}
}
void test(node*& node1, // reference to pointer
node* node2){
delete node1; // Free storage currently used by node1
// But what of the nodes that could be in its tree?
// Think on this. Ask another question if necessary.
// this is where the simple way starts to fall down
node1 = clone(node2);
}
int main(){
struct node* a1 = new node; // wasted memory. We're about to replace it.
// need a more complicated tree to prove deep copy works
struct node* a2 = new node{3,
new node{4, nullptr, nullptr}, // a right node
nullptr}; // no left node
// a2->number = 3; done above now
test(a1 , a2);
std::cout << a1->number << ' '
<< a1->right_child->number;
delete a1; // clean up
delete a2;
}
使用The Rule Of Three 和The Copy and Swap Idiom 的更复杂的规范C++ 方式
#include <iostream>
#include <algorithm> // for std::swap
struct node{
int number = 0;
node* right_child = nullptr; // nullptr safer than NULL
node* left_child = nullptr;
static node * clone(node * src)
{
if (src)
{
return new node(*src);
}
return nullptr;
}
// generic constructor
node(int number = 0,
node* right_child = nullptr,
node* left_child = nullptr):
number(number),
right_child(right_child),
left_child(left_child)
{
}
//copy constructor
node (const node & src):
number(src.number),
right_child(clone(src.right_child)),
left_child(clone(src.left_child))
{
}
// assignment operator via copy and swap.
node & operator=(node src)
{
std::swap(number, src.number);
std::swap(right_child, src.right_child);
std::swap(left_child, src.left_child);
return *this;
}
// destructor
~node()
{
delete right_child;
delete left_child;
}
};
void test(node* node1,
node* node2){
*node1 = *node2; // now, thanks to all of the infrastructure above, we can
// assign nodes with the dumb old = operator. All we have to do
// is dereference the pointers.
}
int main(){
struct node* a1 = new node; // wasted memory. We're about to replace it.
// need a more complicated tree to prove deep copy works
struct node* a2 = new node{3,
new node{4, nullptr, nullptr}, // a right node
nullptr}; // no left node
// a2->number = 3; done above now
test(a1 , a2);
std::cout << a1->number << ' '
<< a1->right_child->number;
delete a1; // clean up
delete a2;
}
所有节点现在都可以自我管理。
但是,我认为,节点应该保持与简单示例中一样的愚蠢。他们根本不需要知道这棵树。树的知识应该在使用节点作为简单容器的Tree 类中。 Tree 类应该对节点进行所有管理——创建、复制、克隆、删除——因为只有它知道代表树所需的一切。树的用户甚至不应该知道节点的存在。他们将数据放入树中,从树中取出数据,然后观察树而不关心树是如何工作的,并且能够做一些像这样愚蠢的事情
delete a_node;
然后把树还没有处理完的数据扔掉。
Tree 类最好以迭代方式而不是递归方式工作,以便可以任意调整树的大小。除非您非常小心地通过一棵大树递归来克隆它、删除它、显示它,或者您对树执行的任何其他操作,否则会冒着耗尽自动存储空间并导致通常称为 Stack Overflow 的风险。