【问题标题】:std::transform a custom tree into a new treestd::将自定义树转换为新树
【发布时间】:2016-09-07 06:41:08
【问题描述】:

我有一个类似树的数据结构定义为:

template<typename T>
struct node {
  T val;
  node<T>* parent;
  unique_ptr<node<T>> next_sibling;
  unique_ptr<node<T>> first_child;
};

template<typename T>
struct tree {
    ...
  private:
    unique_ptr<node<T> _head;
};

我还为树类定义了几个迭代器(preorder、inorder...)。

在给定的树上使用std::transform 可以:

tree<int> t;
...
std::transform(t.begin(), t.end(), t.begin(), [](){});

但是我知道想要拥有类似于 back_inserter 的东西来构建具有相同层次结构的新树:

tree<int> t_n;
std::transform(t.begin(), t.end(), my_inserter(t_n));

如何做到这一点?

【问题讨论】:

  • 但它并不是真正的常规back_inserter,因为它不是线性结构——树有分支。我认为 std::transform 很难做到这一点。
  • 我知道back_inserter 是线性的——这正是我正在努力解决的问题:)。
  • 那么为什么你觉得你必须使用std::transform?

标签: c++ c++11 stl iterator c++14


【解决方案1】:

好吧,这完全取决于您是否可以定义back_inserter

可以做到,但不能使用value_type = T。问题是一个普通的序列不包含足够的信息来重建树的形状(除了像二叉堆这样的特殊情况)。

因此,您必须遍历组成节点值的不同值类型以及有关树形状的一些信息。我看到两个选项:

  • 在 T (boost::option&lt;T&gt;) 周围使用可为空的包装器,并在每个节点之后序列化 next_sybling 和 first_child,如果不存在,则为 none,或者
  • 使用附加标志指定节点是否有子节点以及是否有更多兄弟节点,例如std::tuple&lt;T, bool, bool&gt;

然后你应该能够在插入器中重建树,使用前序迭代,最好是深度优先,但广度优先也可以。无论哪种方式,您都必须在插入器中保持与读取迭代器中相同的迭代状态,因此这将是相当多的代码。

【讨论】:

  • 非常感谢您的回答!您能否更详细地解释这两点 - 不幸的是,我无法真正看到所有这些应该如何结合在一起。你的意思是替换tree_node中的value_type
  • @j.dog,不,在迭代器中。当您取消引用迭代器时,您会得到一些东西。通常它是对T 的某种引用。但在这种情况下,您需要一些额外的信息才能重建树。我称它为value_type,因为它是std::iterator_traits&lt;I&gt;::value_type 的值(默认为typename I::value_type),其中I 是正在使用的迭代器。
  • 我也可以尝试让迭代器返回一个node 并重载将节点转换为值的隐式转换运算符?
  • @j.dog,您可以根据需要使迭代器返回一个节点。但是你不能做隐式转换,因为插入操作符还需要树形信息,这意味着信息必须通过变换函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-18
  • 2019-07-09
  • 2019-11-05
  • 2012-10-11
  • 2021-08-07
  • 2016-06-27
  • 1970-01-01
相关资源
最近更新 更多