web-dev-qa-db-ja.com

C ++でのツリーの最も効率的な実装

各要素が任意の数の子要素を持つツリーを作成する必要があります。このため、ツリーの各ブランチは任意の長さを持つことができます。

ツリーは最初は要素を受け取るだけで、その後は特定の順序で分岐していなくても、反復のために排他的に使用します。

ツリーには数百万の要素があり、高速である必要がありますが、メモリ効率も高くなければなりません。

私の計画では、要素とその子へのポインタを格納するノードクラスを作成します。ツリーが完全に構築されると、それは配列またはより高速なものに変換され、可能であればプロセッサーのキャッシュにロードされます。

ツリーの構築と検索は、2つの異なる問題です。それぞれの問題を個別に最善の方法で解決する方法に集中できますか?の構築は可能な限り高速である必要がありますが、メモリは自由に使用できます。次に、ツリーのブランチを反復するときにスピードを与えるフォーマットへの変換。これは、RAM)からツリーの各要素にキャッシュするのを回避するために、配列であることが望ましいです。

したがって、実際の問題は、挿入速度を最大化するためにツリーを実装するための構造です。それを、最高の速度とメモリを提供する構造にどのように変換できますか?

4
Topo

ノードごとに任意の数の子を持つ更新可能なツリーを実装する自然な方法は、「左側」リンクがノードの最初の子を指し、「右側」リンクが次の子を指すようにバイナリツリーを再解釈することです。同じ親。これにはノードごとに2つのリンクが必要で、特定の子を見つけるために線形リストトラバーサルが必要です。ただし、子の順序が重要でない場合は、子リストの先頭に各子を挿入できます。

特定のノードのすべての子をサブベクトルに連結し、反復のために右側のリンクを削除することにより、ノードごとに1つのリンクのみを持つ読み取り専用ツリーを構築できます。読み取り専用ノード構造の一部として、ブールlast_childフラグまたはchild_countフィールドのいずれかを含める必要があります。 child_countバージョンでは、子リストへのランダムアクセスが許可されることに注意してください。

読み取り専用クエリが長い子リストを頻繁に反復する場合、これによりキャッシュの使用率が劇的に向上する可能性があります。または、読み取り専用クエリが深さ優先で頻繁に反復する場合は、すべての最初の子チェーンを連結して、反復を優先してleft-handリンクを削除する方が効率的です。サブベクトル。

どちらの場合でも、STL vector<>を使用して、読み取り専用ツリーのメモリ管理を行うことができます。更新可能なツリーを(適切な順序で)トラバーサルし、Push_back()を使用します。各ツリーノードの読み取り専用バージョンを順番に追加します。要素をプッシュするとvector<>が再割り当てされる可能性があるため、リンクにはポインタではなくインデックスを使用する必要があることに注意してください。

最後に、読み取り専用ノード構造のサイズを最小化すると、パフォーマンスが向上します。読み取り専用ノードに元のデータ構造へのリンクが含まれている場合は、クエリのトラバーサル中に不要で、クエリがターゲットを見つけた場合にのみ使用されるデータを有益に取り除くことができます。 (考えてみてください、更新可能なツリーもこれから利益を得るかもしれません。)

6
comingstorm