web-dev-qa-db-ja.com

C ++ STLが「ツリー」コンテナを提供していないのはなぜですか?

C++ STLが「ツリー」コンテナを提供していないのはなぜでしょうか。

パフォーマンスの向上としてツリーを使用するのではなく、オブジェクトの階層をツリーとして格納したいのですが。

348
Roddy

ツリーを使う理由は2つあります。

あなたは木のような構造を使って問題を反映したいと思います:
これには、 ブーストグラフライブラリ があります。

あるいは、アクセス特性のようなツリーを持つコンテナが欲しいのです。

基本的に、これら2つのコンテナの特性は、実際にはツリーを使用して実装する必要があるということです(実際には要件ではありません)。

この質問も参照してください。 Cツリーの実装

174
Martin York

おそらくboostにはツリーコンテナが存在しないのと同じ理由が考えられます。そのようなコンテナーを実装するには多くの方法があり、それを使用するすべての人を満足させるための良い方法はありません。

考慮すべきいくつかの問題:
- ノードの子の数は固定か可変か
- ノードあたりのオーバーヘッド量 - つまり、親のポインタ、兄弟のポインタなどが必要ですか。
- 提供するアルゴリズム - 異なるイテレータ、検索アルゴリズムなど.

結局、問題は結局のところ、誰にとっても十分に役に立つツリーコンテナは、それを使う人々の大部分を満足させるには非常に重すぎるということになるでしょう。あなたが何か強力なものを探しているなら、 Boost Graph Library は本質的にツリーライブラリが使われることができるもののスーパーセットです。

これが他の一般的な木の実装です:
- Kasper Peetersのtree.hh
- アドビの森
- core :: tree

89
Greg Rogers

STLの理念は、コンテナがどのように実装されているかではなく、保証に基づいてコンテナを選択することです。例えば、コンテナーの選択は高速検索の必要性に基づいているかもしれません。気になることはありませんが、コンテナは単方向リストとして実装できます。検索が非常に高速である限り、満足できます。これは、内部には何も触れていないためです。アクセスには反復子またはメンバー関数を使用しています。あなたのコードは、コンテナの実装方法ではなく、それがいかに速いか、または固定され定義された順序を持っているかどうか、あるいはスペースを効率的に使うかどうかなどに縛られません。

50
wilhelmtell

「オブジェクトの階層をツリーとして保存したい」

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アルゴリズム を使用して作業すると、状況が複雑になる可能性があります。あなたはあなた自身のイテレータを構築していくらかの互換性を達成することができます、しかし多くのアルゴリズムは単に階層に対して意味を成しません(例えば、範囲の順序を変えるもの)。階層内の範囲を定義したとしても、面倒な作業になる可能性があります。

45
nobar

RBツリーの実装を探しているなら、 stl_tree.h があなたにも適切かもしれません。

42
systemsfault

std :: mapは 赤黒の木 に基づいています。他の コンテナ を使ってあなた自身のタイプの木を実装することもできます。

12
J.J.

ある意味では、std :: mapはツリーです(バランスのとれたバイナリツリーと同じパフォーマンス特性を持つ必要があります)が、他のツリー機能を公開することはありません。実際のツリーデータ構造を含まないことの背後にある可能性のある推論は、おそらくstlにすべてを含まないことの問題です。 stlはあなた自身のアルゴリズムとデータ構造を実装するのに使用するフレームワークと見なすことができます。

一般的に、必要な基本的なライブラリ機能がある場合、それがstlには含まれていません。修正方法は BOOST です。

それ以外の場合は、ツリーのニーズに応じて、 of ライブラリoutthere となります。

8
Eclipse

すべてのSTLコンテナは、1つの反復メカニズムを持つ「シーケンス」として外部的に表現されます。木はこのイディオムに従わない。

6

これは有望に見え、あなたが探しているもののようです: http://tree.phi-sci.com/

4
roffez

STLは「すべて」のライブラリではないためです。それは本質的に、ものを作るのに必要な最小限の構造を含みます。

4
Paul Nathan

私は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
{};

空の集合、ベクトル、またはリストコンテナが適切になるように、イテレータの設計など、ツリー間で定義できる製品および副産物の操作について考慮する必要があります。デフォルトの場合、ペイロードは本当に空です。

木は多くの数学的構造において本質的な役割を果たしています(それらを結合することができる例とそれらを列挙するためにどのように使われるかについてはブッチャー、グロスマンとラーセンの古典的な論文も参照)。彼らの役割が単に特定の他の操作を容易にすることであると考えるのは正しくありません。むしろそれらはデータ構造としてのそれらの基本的役割のためにそれらのタスクを容易にする。

しかし、木に加えて「共木」もあります。何よりも上の木には、根を削除すればすべてを削除するという性質があります。

ツリー上のイテレータを考えてみましょう。おそらく、それらは単純なイテレータのスタックとして、ノードへ、そして親へ、そしてルートまで実現されるでしょう。

template<class TREE>
struct node_iterator : std::stack<TREE::iterator>{
operator*() {return *back();}
...};

しかし、あなたは好きなだけ持つことができます。これらは集合的に「木」を形成しますが、すべての矢印がルートに向かう方向に流れる場合、このコツリーは反復子を通して自明なイテレータとルートに向かって繰り返すことができます。ただし、それを横切ったり下に移動したりすることはできません(他のイテレータはそれを認識していません)。また、すべてのインスタンスを追跡する以外に、イテレータの集合を削除することはできません。

木は非常に便利です、彼らは多くの構造を持っている、これはそれが決定的に正しいアプローチを取得することは深刻な課題になります。私の考えでは、これがSTLに実装されていない理由です。さらに、過去において、私は人々が宗教的になり、それ自身の型のインスタンスを含む型のコンテナのアイデアが挑戦的であることに気づいた - しかし彼らはそれに直面しなければならない。 (小さい)木の空のコレクションcontainer<B>のデフォルトのコンストラクタがBなどのためにヒープ上(または他の場所)にスペースを割り当てない限り、現在の言語では問題なく使用できます。

これが、良い形で、標準への道を見いだしたならば、私は1人のために私は嬉しく思います。

2
tjl

IMO、省略しかし、STLにツリー構造を含めないのにはもっともな理由があると思います。ツリーの管理には多くのロジックがあります。これはメンバー関数としてベースのTreeNodename__オブジェクトに記述するのが最善です。 TreeNodename__が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); } 
} ;
2
bobobobo