如何在C ++函数中构造二叉树并将其返回?

时间:2013-06-04 04:51:59

标签: c++

我在C ++中创建了一个简单的二叉树结构:

template <class T>
struct MyBinaryTree {
  T val;
  BinaryTree<T>* left;
  BinaryTree<T>* right;
  BinaryTree<T>(T v, BinaryTree<T>* l, BinaryTree<T>* r)
      : val(v), left(l), right(r) {}
};

我想编写一个创建二叉树并返回它的函数。不幸的是,这个结构包含指针。因此,如果我在堆栈上返回二叉树,则指针将变得无关紧要。

我有办法返回二叉树结构吗?

3 个答案:

答案 0 :(得分:2)

正如其他人所说,您需要利用动态分配。使用new时,您通常需要遵守Rule of Three, Four, or Five。这意味着您需要决定销毁,复制构造,分配,移动构造和移动分配应如何表现,并实施它们。通常,对于容器,您需要深层复制语义。即使你使用智能指针使破坏变得简单,你也需要做更多的事情才能使副本更深。

但是,不一定需要new来应用动态内存分配。例如,您可以使用list<>来代表leftright,而这样做可以自动为您提供深层复制语义:

template <typename T>
class MyBinaryTree {
    T val_;
    std::list< MyBinaryTree<T> > left_;
    std::list< MyBinaryTree<T> > right_;

    template <typename U>
    friend MyBinaryTree<U> MakeMyBinaryTree (U v,
                                             MyBinaryTree<U> *l = 0,
                                             MyBinaryTree<U> *r = 0) {
        MyBinaryTree<U> t;
        t.val_ = v;
        if (l) t.left_.push_back(*l);
        if (r) t.right_.push_back(*r);
        return t;
    }

public:
    MyBinaryTree<T>* left () { return left_.empty() ? 0 : &*left_.begin(); }
    MyBinaryTree<T>* right () { return right_.empty() ? 0 : &*right_.begin(); }
    T & val () { return val_; }
};

MyBinaryTree<int> make_a_tree ()
{
    MyBinaryTree<int> n1 = MakeMyBinaryTree(1);
    MyBinaryTree<int> n3 = MakeMyBinaryTree(3);
    return MakeMyBinaryTree(2, &n1, &n3);
}

而不是list<>,您可以使用Boost.Optional,或者如果您可以使用C ++ 14,std::optional

答案 1 :(得分:1)

您创建了一个动态容器 - 例如。一个,在运行时构建的。在这种结构的情况下,您必须动态分配它们并使用指针来引用它们。那就是:

MyBinaryTree * BuildSimpleTree()
{
    BinaryTree<int> * node1 = new BinaryTree(0, nullptr, nullptr);
    BinaryTree<int> * node2 = new BinaryTree(0, nullptr, nullptr);

    return new MyBinaryTree<int>(0, node1, node 2);
}

MyBinaryTree * tree = BuildSimpleTree();

动态分配要求背后的原因是当您离开函数或方法时,所有本地静态分配的对象(例如,驻留在堆栈而不是堆上)会自动销毁。但是,为了使树正常工作,它的所有子节点(以及递归子节点)在从函数返回后仍然保持活动状态,因此必须动态分配它们。

您必须记住释放已分配类的所有实例。这可以手动或自动递归完成 - 在BinaryTree和MyBinaryTree dtors中。


如果你能够使用C ++ 11编译你的代码,总会有一个选项来使用移动语义 - 你将能够按值返回树,同时保持代码快速和内存效率。此解决方案如下所示:

template <class T>
struct MyBinaryTree 
{
    T val;
    BinaryTree<T>* left;
    BinaryTree<T>* right;
    BinaryTree<T>(T v, BinaryTree<T>* l, BinaryTree<T>* r)
      : val(v), left(l), right(r) 
    {
    }

    BinaryTree<T>(BinaryTree<T> && r)
    {
        val = r.val;
        left = r.left;
        right = r.right;
    }
};

然后,您可以按值返回树(但仍然动态构建节点):

MyBinaryTree BuildTree()
{
     auto left = new BinaryTree<int>(0, nullptr, nullptr);
     auto right = new BinaryTree<int>(0, nullptr, nullptr);
     MyBinaryTree<int> result(0, left, right);
     return result;
}

答案 2 :(得分:1)

您需要动态分配数据。例如创建

  2
 / \
1   3

使用您的结构,您将执行以下操作:

MyBinaryTree<int>* getTestStructure(){
   MyBinaryTree<int> *root = new MyBinaryTree<int>(2);
   MyBinaryTree<int> *leftChild = new MyBinaryTree<int>(1);
   MyBinaryTree<int> *rightChild = new MyBinaryTree<int>(3);
   root.left = leftChild;
   root.right = rightChild;
   return root;
}