【问题标题】:Is there is a way to go through linked list , where instead of normall pointers will be unique?有没有办法通过链表,而不是普通的指针是唯一的?
【发布时间】:2019-03-25 00:53:37
【问题描述】:

我正在尝试用 c++ 编写二叉树,链表作为子树,唯一指针作为这些列表之间的连接。整个树分为两部分:右和左。有两个指针指向从头到左和到右叶。然后子树中的每个叶子都是一个结构,它存储下一个信息:

class Leaf{
private:
    int * leaf_value; 
    int occupancy;
    std::unique_ptr<Leaf> NextLeaf;

public:
    explicit Leaf(int);
    void AppendLeaf(int,std::unique_ptr<Leaf>);

};

Leaf::Leaf(int size) {
    leaf_value = new int (size);
    NextLeaf = nullptr;
    occupancy = 0;
}

其中leaf_value 是一个指向内存的指针,它将存储该级别上的所有数字。(因为它是一棵二叉树,我们可以知道应该为对象分配的确切大小(2 ^ current_level))。因此,我们将用数字填充该空闲空间,直到占用率小于2 ^ current_level。之后,我们将为下一行元素添加一个新的更深层次。 结构将如下所示:

               1
            /        \
         [2]         [ 3 ]
        /              \
   [4 , 5 ,6 ,7]  [8 , 9 , 10 , 11 ]

方形 bruckets 中的元素是单叶。 .我认为用 uniwue 指针将它们全部连接起来可能是个好主意,因为列表的每个节点只引用下一个节点,所以实际上所有指针都是唯一的。这是我正在尝试做的简化代码。


int main(){
     Node head;
     head.next = nullptr;
     int value;
     cin << value;
     AddNode(value , head); 
     return 0;
}

/*TreeHead - is another leaf structure that stores pointers to left and right branches 
struct SmartTree{
    int level;
    std::unique_ptr<Leaf> LeftChild = std::make_unique<Leaf>(1);
    std::unique_ptr<Leaf> RightChild = std::make_unique<Leaf>(1);

}
*/
void AddNode(int val , std::unique_ptr<SmartTree> TreeHead){
/*problem with implemantation of this part */
     Node * currentLeaf  = TreeHead;
     Node * previousLeaf = TreeHead;
     while(current != nullptr){
        previousLeaf = currentLeaf;
        currentLeaf = currentLeaf -> next ;
     }
     currentLeaf = new Leaf;
     previous -> next = currentLeaf;
     currentLeaf -> value = val; 
}

但问题是,由于唯一指针的唯一性,我无法找到正确的方法来遍历所有最小值。我不确定我是否可以使用 move(pointer) 函数来做到这一点,因为作为我知道功能起作用,它将所有权从TreeHead 借给CurrentLeafe,存储的价值可能会丢失。 所以问题是: 有没有办法通过唯一指针或者我应该使用不同类型的指针来完成该任务? 非常感谢!

【问题讨论】:

  • 您应该从所有权的角度考虑智能指针。在这种情况下,想想“一个节点是否拥有下一个节点”,如果你正在制作一个双向链表,你可以立即看到答案是否定的,因为它们必须相互拥有。我可以从您的示例中告诉您,leaf_value 是使用 unique_ptr 存储的更好候选对象,是的,节点确实拥有该值。
  • 我很确定它“可以”完成,但是您可以做的事情会有很多严重的限制,并且严重限制了界面。另外,我不认为您使用“叶子”这个词来表示我们通常的意思。
  • 那么更好的方法是将叶子存储在共享指针中,(因为树是一个动态结构,将来可以删除叶子,共享指针将允许通过树到达最后一个节点)。并使用唯一指针来存储变量leaf_value?
  • 您似乎混淆了树和列表。您的代码是两个列表,而不是列表树。此外,您给出了Leaf 的定义而不是Node,并且SmartTree 与任何一个都无关。

标签: c++ unique-ptr


【解决方案1】:

我通过在 normal 上更改数组叶子 [ 1 2 3 ] 稍微改变了我的方法。这意味着现在每个叶子都是一个包含一个元素的对象,所以树现在看起来不像:

                1
            /        \
         [2]         [ 3 ]
        /              \
   [4 , 5 ,6 ,7]  [8 , 9 , 10 , 11 ]

但喜欢:

               1
           /       \
          2           3
        /    \      /  \ 
       5      6    7     8 

新的树结构:

struct SmartTree {
    int value;
    int childrens;
    bool is_root = false;
    std::unique_ptr<SmartTree> LeftChild;
    std::unique_ptr<SmartTree> RightChild;
};

但我相信它也可以与以前的方法一起使用。所以我发现,在这种情况下,一个好的解决方案是递归,而不是没有帮助,现在函数遍历树并将元素添加到末尾看起来像这样:

std::unique_ptr <SmartTree> InsertLeftChild(std::unique_ptr<SmartTree> tree, std::unique_ptr<SmartTree> left_subtree){
    // left_subtree - node to insert
    tree -> childrens += 1;
    if (tree -> is_root and  tree -> LeftChild == nullptr) tree -> LeftChild = std::move(left_subtree);
    else if (tree -> is_root) tree -> LeftChild = InsertLeftChild(std::move(tree -> LeftChild) , move(left_subtree));
    else if (tree -> LeftChild == nullptr)tree -> LeftChild = std::move(left_subtree);
    else if (tree -> RightChild == nullptr) tree -> RightChild = std::move(left_subtree);
    else if (tree -> LeftChild -> childrens <= tree -> RightChild -> childrens) tree->LeftChild = InsertLeftChild(std::move(tree -> LeftChild) , std::move(left_subtree));
    else if (tree -> LeftChild -> childrens > tree -> RightChild -> childrens)  tree->RightChild = InsertLeftChild(std::move(tree -> RightChild) , std::move(left_subtree));
    return move(tree);
};

这只是为了插入左孩子而写的。所以第一个和第二个if 检查它是否是一个根,这个根是否初始化。如果它有 childs ,则调用函数 InsertLeftChilld 。传递参数,使用 move 函数将破坏先前的指针,所以在左侧我将所有权归还给 LeftChild:

tree -> LeftChild = std::move(left_subtree);

else if (tree -&gt; LeftChild == nullptr) 检查它是否结束,如果是 - 插入新的叶子

else if (tree -&gt; LeftChild -&gt; childrens &lt;= tree -&gt; RightChild -&gt; childrens) 检查你接下来应该将你的叶子指向哪里,以防它不水平你可以插入它 .希望这个方法能对以后的人有所帮助。谢谢大家的回答!

【讨论】:

    猜你喜欢
    • 2021-08-26
    • 1970-01-01
    • 2013-08-05
    • 1970-01-01
    • 2020-12-18
    • 2016-11-23
    • 1970-01-01
    • 2022-07-14
    • 2013-03-31
    相关资源
    最近更新 更多