【问题标题】:How to iterate over a non-linear container如何迭代非线性容器
【发布时间】:2013-10-21 16:31:23
【问题描述】:

考虑一个层次树结构,其中一个项目可能有兄弟项目(在层次结构中的同一级别),也可能有子项目(在层次结构中向下一级)。

假设结构可以定义为:

// an item of a hierarchical data structure
struct Item {
    int          data;     // keep it an int, rather than <T>, for simplicity
    vector<Item> children;
};

我希望能够在此结构上使用算法,例如 std::map、std::vector 等的算法。因此,我创建了一些算法,例如:

template <class Function>
Function  for_each_children_of_item( Item, Function f );  // deep (recursive) traversal

template <class Function>
Function  for_each_direct_children_of_item( Item, Function f );  // shallow (1st level) traversal

template <class Function>
Function  for_each_parent_of_item( Item, Function f );  // going up to the root item

困扰我的一件事是同一个结构有 3 个for_each() 函数。但是他们很好地描述了他们如何迭代,所以我决定接受它。

然后,很快就出现了对更多算法的需求(如find_ifcount_ifany_of 等),这让我觉得我在设计方面没有走上正轨。

我能想到的一种可以减少工作量的解决方案是简单地编写:

vector<Item>  get_all_children_of_item( Item );         // recursive
vector<Item>  get_all_direct_children_of_item( Item );  // 1st level items
vector<Item>  get_all_parents_of_item( Item );          // up to the root item

然后我可以使用所有的 STL 算法。 我对这个解决方案有点警惕,因为它涉及复制。

我想不出实现iterator 的方法,因为在递归版本的遍历中没有明显的end() 迭代器。

  • 谁能提出一种典型/惯用的方法来处理这种非线性数据结构?
  • 可以/应该为这样的结构创建迭代器吗?怎么样?

【问题讨论】:

  • std::map 采用迭代器路由。它确实适用于树,但我不是谷歌工作面试的专家,所以我现在没有记住任何无用的树算法。 :) 您的直觉是正确的,因为您想要查看数据,而不是数据的副本。所以我会专注于研究如何在树上从左到右工作。 :)
  • 是的,迭代器在这里是合适的。例如,这就是您将算法应用于std::map 的内容的方式,即使它是作为二叉树实现的。无需复制数据;只需在增量运算符中编写适当的遍历代码即可。
  • Map 可以迭代,因为它有指向父节点的指针。可以在不向结构添加额外数据的情况下完成吗?我无法更改这部分代码。
  • 对于std::map,树对用户是隐藏的。对于迭代,它的行为就像一个“平面”容器(例如,像一个链表)。如果您想迭代树中类似于std::map 的所有节点,您可以查看libstdc++ 的_Rb_tree_increment,它实现了std::map 的迭代。
  • @Grim 如果您无法更改结构,您可能必须在迭代器中存储额外的状态 - 例如从根目录到您所在位置的路径中的所有Items。

标签: c++ stl


【解决方案1】:

使用迭代器。

我想不出实现迭代器的方法,因为在遍历的递归版本中没有明显的 end() 迭代器。

end() 可以是迭代器类的任何指定特殊值,只要您的增量运算符在跳过最后一个元素时产生它。和/或为您的迭代器覆盖运算符 ==/!=

如果您想真正健壮,请为每个 XPath axes 实现一个迭代器模式。

【讨论】:

  • 所以,你的意思是我应该为子到父轴创建一个单独的迭代器,为 item-to-all_children 轴创建另一个迭代器,等等?这是否意味着结构本身应该具有从子级到父级以及从项目到下一个(或上一个)兄弟的指针?似乎应该有相当多的内部链接,只是为了有一个迭代器。迭代器旨在分离数据结构和算法之间的耦合,但这将过多的负担转移到数据结构本身......
  • 既然您提到已经拥有get_all_parents_of_item,我假设您已经拥有这样的父链接。如果没有,则无需支持这些轴。
猜你喜欢
  • 2021-01-09
  • 2021-04-04
  • 1970-01-01
  • 2011-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多