从矢量创建树

时间:2018-03-13 04:01:05

标签: c++ algorithm binary-tree smart-pointers

我正在使用符号计算器。但是为了给出一个可验证的小例子,我把它分解为下面的例子,起初看起来可能很奇怪。

我有一个点{1,4,4,8,5,7}的列表,我会迭代。我在每次迭代中都读了两点。 我希望这段代码能做的是:
迭代1:没有树,所以我们创建一个。我们对4进行了参考。

  4
 /
1

迭代2: 8大于最后一个引用(4)。所以我们制作

  8
 /
3

4岁的右孩,并在8

上保留参考
    4
  /   \
 1      8
       /
      3

迭代3: 7小于最后一个引用(8)所以我们返回直到找到小于4的数字(或到达根目录)。然后我们创建节点

 7
  \
   5

并将最后一个引用添加为左子项。

     7
   /   \
  4      5
 /  \
1    8
    /
   3

请注意:我这里并不关心特殊情况等。我很积极,一旦我开始工作,我就可以自己解决这个问题。

这是我的树类:

#ifndef NODE_H
#define NODE_H

#include <memory>
#include <string>

template<typename T>
class Node : public std::enable_shared_from_this< Node<T> >{
    public:
        typedef std::shared_ptr< Node<T> > NodePtr;
        typedef std::weak_ptr< Node<T> > NodeWPtr;

        T data;
        NodePtr left, right;
        NodeWPtr parent;

        Node(){}
        Node(const T& data) : data(data){}
        Node(const T& data, NodeWPtr parent) : data(data), parent(parent){}
        Node(const T& data, NodeWPtr parent, NodePtr& left) : data(data), parent(parent), left(left){
            left->parent = this->shared_from_this();
        }
        Node(const Node& n) : data(n.data), left(n.left), right(n.right){}
        Node& operator=(const Node&) = delete;
        ~Node() = default;

        NodePtr findRoot(){
            if( parent.lock() ){
                return parent.lock()->findRoot();
            }
            return this->shared_from_this();
        }

        void print(int indent=0){
            std::cout << data << std::endl;
            std::cout << std::string(2*indent+2, '-') << "L: ";
            if( left ){
                left->print(indent+1);
            }
            std::cout << std::endl;
            std::cout << std::string(2*indent+2, '-') << "R: ";
            if( right ){
                right->print(indent+1);
            }
            if( indent==0 ) std::cout << std::endl;
        }
};

#endif // NODE_H

这是我的main.cpp

#include <iostream>
#include <vector>

#include "Node.h"

int main(){
    typedef std::shared_ptr< Node<int> > NodePtr;
    NodePtr last;
    std::vector<int> list {1, 4, 3, 8, 5, 7};
    for( unsigned int i = 0; i < list.size(); i += 2 ){
        if( !last ){
            last = std::make_shared< Node<int> >(Node<int>(list.at(i+1)));
            last->left = std::make_shared< Node<int> >(Node<int>(list.at(i), last));
            continue;
        }
        if( list.at(i+1) >= last->data ){
            NodePtr newNode = std::make_shared< Node<int> >(Node<int>(list.at(i+1)));
            newNode->left = std::make_shared< Node<int> >(Node<int>(list.at(i)));
            last->right = newNode;
            newNode->parent = last;
            newNode->findRoot()->print();
            last = newNode;
            last->findRoot()->print();
        }else{
            while( !last->parent.expired() && last->data < list.at(i+1) ){
                last = last->parent.lock();
            }
            NodePtr newNode = std::make_shared< Node<int> >(Node<int>(list.at(i+1)));
            newNode->right = std::make_shared< Node<int> >(Node<int>(list.at(i)));
            newNode->left = last;
            last->parent = newNode;
            last = newNode;
        }
    }
    last->findRoot()->print();
}

当我在第二次迭代中复制它时,不知何故4-1分支被删除了。它在第一次印刷中仍然存在,但在复制后,它已经消失了。

1 个答案:

答案 0 :(得分:1)

问题在于以下一行

newNode->parent = last;
newNode->findRoot()->print();
last = newNode;

最初,只有shared_ptr last指向节点4.将newNode分配给last后,不再有指向节点4的shared_ptr。这导致节点8中的weak_ptr parent到期。因此,当您调用last->findRoot()(此处为节点8)时,它无法返回节点4.

您的数据结构可确保除了根目录之外的每个节点至少由1个shared_ptr(其父节点)指向。因此,您需要手动将shared_ptr保存到根节点。