从矢量创建树
Create Tree from Vector
我正在研究符号计算器。但是为了给出一个可验证的小例子,我把它分解成下面的例子,乍一看可能看起来很奇怪。
我有一个要迭代的点列表 {1, 4, 3, 8, 5, 7}。我在每次迭代中读了两点。
我想要这段代码做的是:
迭代 1: 没有树,所以我们创建一棵。我们保留 4 号的参考。
4
/
1
迭代 2: 8 大于最后一个引用 (4)。所以我们
8
/
3
4 的权利 child 并保留 8
的参考
4
/ \
1 8
/
3
迭代 3: 7 小于最后一个引用 (8) 所以我们返回直到找到小于 4 的数字(或到达根)。然后我们创建节点
7
\
5
并将最后一个引用添加到此 child。
7
/ \
4 5
/ \
1 8
/
3
请注意:我不关心这里的特殊情况等。我很肯定我可以自己解决这个问题,一旦我开始工作。
这是我的树 class:
#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();
}
当我在第 2 次迭代中复制 4-1 分支时,不知何故被删除了。第一次打印的时候还在,复制之后就没了
问题出在下面这几行
newNode->parent = last;
newNode->findRoot()->print();
last = newNode;
一开始只有shared_ptrlast
指向节点4,你把newNode
赋值给last
后,就没有shared_ptr指向节点4了了。这导致节点 8 中的 weak_ptr parent
过期。因此,当您调用 last->findRoot()
(最后这里是节点 8)时,它无法 return 节点 4.
您的数据结构确保除根节点外的每个节点至少由 1 shared_ptr(其父节点)指向。所以你需要手动保留一个shared_ptr到根节点。
我正在研究符号计算器。但是为了给出一个可验证的小例子,我把它分解成下面的例子,乍一看可能看起来很奇怪。
我有一个要迭代的点列表 {1, 4, 3, 8, 5, 7}。我在每次迭代中读了两点。
我想要这段代码做的是:
迭代 1: 没有树,所以我们创建一棵。我们保留 4 号的参考。
4
/
1
迭代 2: 8 大于最后一个引用 (4)。所以我们
8
/
3
4 的权利 child 并保留 8
的参考 4
/ \
1 8
/
3
迭代 3: 7 小于最后一个引用 (8) 所以我们返回直到找到小于 4 的数字(或到达根)。然后我们创建节点
7
\
5
并将最后一个引用添加到此 child。
7
/ \
4 5
/ \
1 8
/
3
请注意:我不关心这里的特殊情况等。我很肯定我可以自己解决这个问题,一旦我开始工作。
这是我的树 class:
#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();
}
当我在第 2 次迭代中复制 4-1 分支时,不知何故被删除了。第一次打印的时候还在,复制之后就没了
问题出在下面这几行
newNode->parent = last;
newNode->findRoot()->print();
last = newNode;
一开始只有shared_ptrlast
指向节点4,你把newNode
赋值给last
后,就没有shared_ptr指向节点4了了。这导致节点 8 中的 weak_ptr parent
过期。因此,当您调用 last->findRoot()
(最后这里是节点 8)时,它无法 return 节点 4.
您的数据结构确保除根节点外的每个节点至少由 1 shared_ptr(其父节点)指向。所以你需要手动保留一个shared_ptr到根节点。