【问题标题】:What are my options implementing a tree data structure?实现树数据结构的选项有哪些?
【发布时间】:2021-09-10 13:10:37
【问题描述】:

我的一个程序需要一个树形结构。我知道以下两种实现方法:

  1. 递归,基于指针。
struct node
{
    std::unique_ptr<T>                 data     = nullptr;
    std::vector<std::unique_ptr<node>> children = {};
};

//       /> leaf_a
// root --> leaf_b  /> leaf_d
//       \> leaf_c --> leaf_e
auto root = std::make_unique<node>();
root->children.emplace_back(std::make_unique<node>(a_data));
root->children.emplace_back(std::make_unique<node>(b_data));
root->children.emplace_back(std::make_unique<node>(c_data));
root->children[2]->children.emplace_back(std::make_unique<node>(d_data));
root->children[2]->children.emplace_back(std::make_unique<node>(e_data));
  1. 基于节点对。
struct tree
{
    std::vector<std::unique_ptr<T>>        data        = {};
    std::vector<std::pair<size_t, size_t>> connections = {};
};


//       /> leaf_a
// root --> leaf_b  /> leaf_d
//       \> leaf_c --> leaf_e
auto boom = tree{};
boom.data.emplace_back(nullptr);
boom.data.emplace_back(a_data);
boom.data.emplace_back(b_data);
boom.data.emplace_back(c_data);
boom.data.emplace_back(d_data);
boom.data.emplace_back(e_data);
boom.connections.emplace_back(std::make_pair(0,1));
boom.connections.emplace_back(std::make_pair(0,2));
boom.connections.emplace_back(std::make_pair(0,3));
boom.connections.emplace_back(std::make_pair(3,4));
boom.connections.emplace_back(std::make_pair(3,5));

当然,这两个例子都可以通过适当的 api 变得更漂亮,但它们只应该展示最基本的实现。

我的问题是: 还有其他方法可以实现树吗?两种方法的优缺点是什么?

注意:我明确需要每个节点有多个子节点的选项,并且每个节点都应该有一个可选的数据字段。

【问题讨论】:

  • 就我个人而言,我会将工作外包;)github.com/kpeeters/tree.hh
  • 谢谢,我去看看。
  • 如果你有一个非常强的假设,即这棵树是一个几乎完全的二叉树,那么你可以方便地将它存储在一个数组中。这就是heaps 通常的实现方式。
  • 第三种可能性是让每个子节点指向其父节点(根节点指向 NULL),而不是每个父节点指向其子节点的列表。
  • std::unique_ptr&lt;T&gt; 指向子节点不一定是个好主意(销毁时存在堆栈溢出的风险)。 std::unique_ptr&lt;T&gt; data = nullptr;十亿美元的错误。使用T data; 并转发构造函数参数。如果您的特定树是指针树,请使用node&lt;std::unique_ptr&lt;whatever&gt;&gt;,但这应该很少见。

标签: c++ data-structures tree


【解决方案1】:

还有其他实现树的方法吗?

您的所有选项都处理动态内存并且不会很好地处理缓存一致性,会产生额外的间接性。这绝对是基于意见的,但我会给你另一种选择

template <typename T>
class Node
{
    T value;
    std::vector<size_t> children; // position in nodes of the children
};

template <typename T>
class Tree
{
    std::vector<Node<T>> nodes;
};

这将所有节点都放在一个连续的块中,并且允许重新设置节点而不复制它们。添加、删除等会带来额外的复杂性。

但这是一个额外的选择。它甚至允许具有循环的奇异树:-)

【讨论】:

  • OP要求每个节点可以有N个叶子。
  • 已编辑。不过,这让它变得不那么简单了。也许 children 可以是一个模板大小的数组。有很多选择。
  • 非常有趣!您的选项与我的第二个选项类似,但更容易找到每个节点的子节点,这应该有利于树遍历。
  • 对于我正在考虑的实际用例,我将花费大量时间遍历树并用扩展版本替换节点。目前我在内存行为方面的想法是将新节点推回std::deque。这将允许我在不复制的情况下扩展树。对于删除,我需要保留一个额外的已删除节点列表,在所有其他步骤完成后我将删除它。但当然需要进行测试和基准测试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-06
  • 2010-10-16
相关资源
最近更新 更多