题
为什么不C++STL不提供任何"树"容器,以及什么是最好的事情来使用,而不是?
我想要保存一个层次的对象一棵树,而不是使用一种树作为增强性能...
解决方案
有两个原因,你可能要使用一棵树:
你要镜子的使用问题树形结构:
为此,我们必须 提高图表的图书馆
或者你想一个容器的有树一样的访问特点 为此,我们必须
std::map
(及std::multimap
)std::set
(及std::multiset
)
基本特点这两个容器就是这样,他们几乎有可实施的使用树木(虽然这实际上不是一个要求)。
也看到这个问题:C树执行情况
其他提示
可能出于同样的原因,没有树容器中的提升。有许多方法来实现这样的容器,并且没有良好的方式满足的人都会使用它。
要考虑的一些问题:
-是的儿童人数为一个节点的固定的或可变的?
-多少开销,每个节点?-即你需要父母的指针,同级的指针,等等。
-什么样的算法来提供?-不同的迭代,搜索算法,等等。
最终,问题的结束是一个树容器,将是有用的足够的每一个人,将会过于重量级,以满足大多数人使用它。如果你是在寻找的东西强大, 提高图表的图书馆 基本上是一个超集一个什么样的树库可用。
这里有一些其他一般的树实现:
- 卡斯帕Peeters'树。hh
- Adobe的森林
- 核心::树
STL的理念是您选择基于保证的容器,而不是基于容器的实现方式。例如,您选择的容器可能基于快速查找的需要。对于您所关心的一切,容器可以实现为单向列表 - 只要搜索速度非常快,您就会感到高兴。那是因为你无论如何都没有触及内部,你正在使用迭代器或成员函数进行访问。您的代码不受容器实现方式的约束,而是绑定到它的速度,或者它是否具有固定和定义的顺序,或者它是否在空间上有效等等。
“我想将对象的层次结构存储为树”
C ++ 11已经过去了,他们仍然没有看到需要提供 std :: tree
,尽管这个想法确实出现了(参见here )。也许他们没有添加这个的原因是,在现有容器之上构建自己的容易起来非常容易。例如......
template< typename T >
struct tree_node
{
T t;
std::vector<tree_node> children;
};
一个简单的遍历将使用递归...
template< typename T >
void tree_node<T>::walk_depth_first() const
{
cout<<t;
for ( auto & n: children ) n.walk_depth_first();
}
如果您想维护层次结构和,您希望它能够与 STL算法一起使用,事情可能会变得复杂。您可以构建自己的迭代器并实现一些兼容性,但是许多算法对层次结构没有任何意义(例如,任何改变范围顺序的东西)。即使在层次结构中定义范围也可能是一个混乱的业务。
如果您正在寻找RB树实现,那么 stl_tree.h 也可能适合你。
所有STL容器在外部表示为“序列”。一个迭代机制。 树木不遵循这个习语。
因为STL不是“一切”。图书馆。它基本上包含构建东西所需的最小结构。
这个看起来很有前途,似乎是你正在寻找的: http://tree.phi-sci.com/
TreeNode
对象。当 TreeNode
被包装在STL标头中时,它会变得更加混乱。
例如:
template <typename T>
struct TreeNode
{
T* DATA ; // data of type T to be stored at this TreeNode
vector< TreeNode<T>* > children ;
// insertion logic for if an insert is asked of me.
// may append to children, or may pass off to one of the child nodes
void insert( T* newData ) ;
} ;
template <typename T>
struct Tree
{
TreeNode<T>* root;
// TREE LEVEL functions
void clear() { delete root ; root=0; }
void insert( T* data ) { if(root)root->insert(data); }
} ;
我认为没有stl树有几个原因。主要树是递归数据结构的一种形式,它像容器(列表,向量,集)一样,具有非常不同的精细结构,这使得正确的选择变得棘手。使用STL,它们也很容易以基本形式构建。
可以将有限的有根树视为具有值或有效负载的容器,例如A类的实例,以及可能为空的根(子)树集合;没有子树的树虽然是叶子。
template<class A>
struct unordered_tree : std::set<unordered_tree>, A
{};
template<class A>
struct b_tree : std::vector<b_tree>, A
{};
template<class A>
struct planar_tree : std::list<planar_tree>, A
{};
人们必须考虑一下迭代器设计等,以及允许在树之间定义和有效的产品和联产品操作 - 并且原始的stl必须写得很好 - 以便空集,矢量或列表容器在默认情况下实际上没有任何有效负载。
树木在许多数学结构中起着至关重要的作用(参见Butcher,Grossman和Larsen的经典论文;还有Connes和Kriemer的论文,例如它们可以加入,以及它们如何被用来枚举)。认为他们的角色只是为了促进某些其他操作是不正确的。相反,由于它们作为数据结构的基本作用,它们促进了这些任务。
然而,除树木外,还有“共树”;上面的树都有这样的属性,如果删除根,你就删除了所有内容。
考虑树上的迭代器,可能它们将被实现为一个简单的迭代器堆栈,一个节点,它的父节点,......直到根节点。
template<class TREE>
struct node_iterator : std::stack<TREE::iterator>{
operator*() {return *back();}
...};
然而,你可以拥有任意多的人;它们共同构成了一棵“树”。但是当所有箭头都朝向根的方向流动时,这个共同树可以通过迭代器迭代到平凡的迭代器和根;但是它不能跨越或向下导航(其他迭代器不为它所知),也不能删除迭代器的集合,除非跟踪所有实例。
树木非常有用,它们有很多结构,这使得获得明确正确的方法成为一个严峻的挑战。在我看来,这就是为什么它们没有在STL中实现的原因。此外,在过去,我看到人们变得宗教,并且发现包含自己类型的实例的容器类型的想法具有挑战性 - 但是他们必须面对它 - 这就是树类型所代表的 - 它是一个包含可能是(较小的)树木的空集合。当前语言允许它没有挑战提供容器的默认构造函数&lt; B&gt;
不在堆(或其他任何地方)为 B
等分配空间。
如果这样做,我会很高兴以良好的形式进入标准。
所有STL容器都可以与迭代器一起使用。你不能让迭代器成为一棵树,因为你没有“一个正确”的方式来穿过这棵树。