使用唯一指针将节点添加到树

Posted

技术标签:

【中文标题】使用唯一指针将节点添加到树【英文标题】:adding nodes to tree with unique pointer 【发布时间】:2018-02-16 15:47:07 【问题描述】:

我对智能指针非常陌生,我正在尝试创建一个双重树,其中子节点通过唯一指针从父节点指向,子节点通过原始指针指向父节点。所以当一个父节点被销毁时,整个子树都会在这个过程中被销毁。

class Node 
private:
    Node *parent;
    std::unique_ptr<Node> left;
    std::unique_ptr<Node> right;
public:
    Node(Node* _left, Node* _right, Node* _parent);
;

Node::Node(Node* _left, Node* _right, Node* _parent) 
    parent = &_parent;

    //this is where the problem starts

我不明白如何指向一个可能有我想要连接的树的新节点。如果我使用 make_unique 我相信这将创建一个新节点而不是保留树。

我可能完全错了,因为我大约 4 天前刚刚学习了智能指针(实际上有足够的时间来学习一些东西)。

【问题讨论】:

你传递给构造函数的东西是节点的副本,这不太可能是你想要的。 值传递的参数与其他局部变量没有区别,一旦函数返回就会超出范围。 构造函数中怎么能左右呢?您正在创建一个节点,同时已经知道父节点和子节点? 好吧,正如我在解释中所说,我想要唯一指针类的唯一属性(如果它超出范围,它将被删除),但同时想要访问其父类。 【参考方案1】:

首先,一棵空树是可能的,并且默认构造的节点很适合。 父节点在附加节点时就知道了,因此,一旦节点被设置为当前树的左子节点或右子节点,子节点的父节点将被更新。

接收 unique_ptr 可能是一个好主意,因为您拥有所接收指针的所有权。这是一个示例实现:

class Node 
private:
  Node *parent = nullptr;
  std::unique_ptr<Node> m_left;
  std::unique_ptr<Node> m_right;

public:

  void left(std::unique_ptr<Node> child) 
    m_left = std::move(child);
    m_left->parent = this;
  

  void right(std::unique_ptr<Node> child) 
    m_right = std::move(child);
    m_right->parent = this;
  
;

你会像下面这样使用它:

int main()

  auto tree = std::make_unique<Node>();
  auto subtree = std::make_unique<Node>();

  subtree->right(std::make_unique<Node>());
  tree->right(std::make_unique<Node>());
  tree->left(std::move(subtree));
  return 0;

我自己对unique_ptr 还很陌生,希望有人能进一步纠正我。 顺便说一句,不要使用以_ 开头的名称作为您的标识,它们是保留的。

【讨论】:

"TW 不要使用以 _ 开头的名称作为您的标识,它们是保留的。"有时。 What are the rules about using an underscore in a C++ identifier? 我不使用它们,因为如果我不小心违反了其中一条规则,我不想要惊喜。 嗯,这也是我的精神。【参考方案2】:

我认为你不能使用:

Node(Node _left, Node _right, Node _parent);

这将不允许逐个节点构建树。相反,使用:

Node(Node* _left, Node* _right, Node* _parent);

这样,您可以使用以下方法创建第一个节点:

Node firstNode(nullptr, nullptr, nullptr);

从那里,您可以构建其他节点。

构建一个简单的树,三个节点如下

            N1
           /  \
         N2    N3

你可以使用:

Node* N1 = new Node(nullptr, nullptr, nullptr);
Node* N2 = new Node(nullptr, nullptr, N1);
Node* N3 = new Node(nullptr, nullptr, N1);

N1->left = N2;  // Use the equivalent member function.
N1->right = N3;

【讨论】:

在构造N1N2N3时最好使用std::unique_ptr&lt;Node&gt;甚至std::make_unique&lt;Node&gt;(),然后将std::move()N2N3转换为@9876543 N1-&gt;right。此外,_left_right 构造函数参数也应该是 std::unique_ptr&lt;Node&gt; 嘿,你是怎么建造那棵树的?我可能会尝试记住如何以这种方式提供更好的问题。 @Dogunboundhounds,你的意思是 ASCII 艺术中的树? @RSahu 是的。我怎么做?在 *** 编辑器中。 @Dogunboundhounds,就像写代码一样。使用字符 /\ 创建连接。不习惯有点乏味,但习惯了就不会那么糟糕了。【参考方案3】:

我相信您想公开父母、左右孩子。至少,这就是我一直使用struct 来实现我的节点的方式:

struct Node

    Node(std::unique_ptr<Node> _parent = nullptr, 
std::unique_ptr<Node> _left = nullptr, std::unique_ptr<Node> _right = nullptr) : parent(_parent), left(_left), right(_right) 

    std::unique_ptr<Node> parent;
    std::unique_ptr<Node> left;
    std::unique_ptr<Node> right;

;

如果我错了,请有人纠正我。

【讨论】:

必然一个Nodeparent将是另一个Nodeleftright。如果有两个指向它的指针,则不是一个非常唯一的指针。 OP 有这部分权利。 @user4581301 啊,这是有道理的。我从来没有真正使用过std::unique_ptr,我一直使用std::shared_ptr,并错误地认为可以以相同的方式使用unique和shared。 用简单的英语描述各种智能指针用途的好答案:***.com/a/30143936/4581301。该问题的第一个答案更详细地说明了如何以及何时使用。 @user4581301 感谢您提供链接。我的教授向我展示了如何使用std::shared_ptr 构建节点,所以如果我们用共享替换所有唯一节点,那会是不好的做法吗?或者如果它完成了工作,这是否可以接受? youtube.com/watch?v=JfmTagWcqoE&t=1864s 转至 22:41。这就是我发布这个问题的原因

以上是关于使用唯一指针将节点添加到树的主要内容,如果未能解决你的问题,请参考以下文章

将节点添加到树 - 为啥根没有被初始化?

VB.NET 如何将子节点添加到树视图中的特定节点

将复选框列添加到树左侧的 QTreeView 的方法?

将图像添加到树视图控件 xamarin 表单中

如何禁止TreeView.ExpandAll方法自动滚动到树的末尾?

跟踪从图的节点到树的最小高度