为什么C++ STL不提供任何"树"容器,而最好使用什么?
我想将对象的层次结构存储为树,而不是使用树作为性能增强...
您可能想要使用树有两个原因:
您希望使用类似树的结构来镜像问题:
为此,我们使用了boost图库
或者你想要一个具有树状访问特征的容器为此我们有
std::map
std::multimap
基本上这两个容器的特征是它们实际上必须使用树来实现(尽管这实际上不是必需的).
另见这个问题: C树实现
可能出于同样的原因,在增强中没有树容器.有很多方法可以实现这样一个容器,并没有很好的方法来满足每个使用它的人.
需要考虑的一些问题:
- 节点的子节点数是固定的还是可变的?
- 每个节点有多少开销?- 即,你需要父指针,兄弟指针等
- 提供什么算法? - 不同的迭代器,搜索算法等
最后,问题最终是一个对每个人都足够有用的树容器,对于大多数使用它的人来说太重了.如果您正在寻找功能强大的东西,Boost Graph Library本质上是树库可用的超集.
以下是一些其他通用树实现:
- Kasper Peeters的tree.hh
- Adobe的林
- 核心::树
STL的理念是您选择基于保证的容器,而不是基于容器的实现方式.例如,您选择的容器可能基于快速查找的需要.对于您所关心的一切,容器可以实现为单向列表 - 只要搜索速度非常快,您就会感到高兴.那是因为你无论如何都没有触及内部,你正在使用迭代器或成员函数进行访问.您的代码不受容器实现方式的限制,而是绑定到它的速度,或者它是否具有固定和定义的顺序,或者它是否在空间上有效等等.
"我想将对象的层次结构存储为树"
C++ 11已经过去了,他们仍然没有看到需要提供一个std::tree
,虽然这个想法确实出现了(见这里).也许他们没有添加这个的原因是,在现有容器之上构建自己的容易起来非常容易.例如...
template< typename T > struct tree_node { T t; std::vectorchildren; };
一个简单的遍历将使用递归...
template< typename T > void tree_node::walk_depth_first() const { cout< 如果您想维护层次结构并希望它与STL算法一起使用,那么事情可能会变得复杂.您可以构建自己的迭代器并实现一些兼容性,但是许多算法对层次结构没有任何意义(例如,任何改变范围顺序的东西).即使在层次结构中定义范围也可能是一项混乱的业务.
事实证明,他们是懒惰的,实际上是你的第一个例子Undefined Behavior.
如果项目可以允许对tree_node的子节点进行排序,那么使用std :: set <>代替std :: vector <>然后将一个运算符<()添加到tree_node对象将大大改善'搜索''T'类对象的表现.
@Mehrdad:我最后决定要求你的评论背后的细节[这里](http://stackoverflow.com/questions/32487575/class-or-struct-self-reference-by-template).
5> systemsfault..:如果您正在寻找RB树实现,那么stl_tree.h也可能适合您.
奇怪的是,这是实际回答原始问题的唯一回应.
考虑到他想要一个"Heiarchy",似乎可以安全地假设任何具有"平衡"的东西都是错误的答案.
"这是一个内部头文件,包含在其他库头文件中.您不应该尝试直接使用它."
@Dan:复制它并不构成直接使用它.
6> J.J...:std :: map基于一棵红黑树.您还可以使用其他容器来帮助您实现自己的树类型.
它通常使用红黑树(不需要这样做).
7> Eclipse..:在某种程度上,std :: map是一棵树(它需要具有与平衡二叉树相同的性能特征),但它不会暴露其他树功能.不包括真实树数据结构的可能原因可能只是不包括stl中的所有内容.可以将stl看作是用于实现自己的算法和数据结构的框架.
一般来说,如果你想要一个基本的库功能,那就不是在stl中,修复就是看看BOOST.
否则,有一个一堆的库 了 那里,这取决于你的树的需求.
8> Emilio Garav..:所有STL容器外部表示为具有一个迭代机制的"序列".树木不遵循这个习语.
树数据结构可以通过迭代器提供预订,顺序或后序遍历.实际上这就是std :: map的作用.
是的,不是......这取决于你对"树"的意思.`std :: map`在内部实现为btree,但在外部它显示为PAIRS的排序SEQUENCE.无论你有什么元素,你都可以普遍地问谁以前和谁在追求.包含元素的一般树结构中的每一个都包含其他元素,不会强加任何排序或方向.你可以定义以多种方式遍历树结构的迭代器(sallow | deep first | last ...)但是一旦你做到了,`std :: tree`容器必须从`begin`函数返回其中一个.并没有明显的理由让一个或另一个回归.
std :: map通常由平衡二叉搜索树表示,而不是B树.您所做的相同参数可以应用于std :: unordered_set,它没有自然顺序,但提供了开始和结束迭代器.开始和结束的要求只是它以某种确定性顺序迭代所有元素,而不是必须有一个自然元素.preorder是树的完全有效的迭代顺序.
你的答案的含义是没有stl n-tree数据结构,因为它没有"序列"接口.这完全是错误的.
@EmiloGaravaglia:由`std :: unordered_set`证明,它没有迭代其成员的"独特方式"(实际上迭代顺序是伪随机和实现定义),但仍然是一个stl容器 - 这反驳了你的观点.即使订单未定义,迭代容器中的每个元素仍然是一项有用的操作.