libwordring
|
木コンテナ [詳解]
#include <wordring/tree/tree.hpp>
公開型 | |
using | value_type = T |
using | allocator_type = Allocator |
using | size_type = std::size_t |
using | difference_type = std::ptrdiff_t |
using | reference = value_type & |
using | const_reference = value_type const & |
using | pointer = value_type * |
using | const_pointer = value_type const * |
using | iterator = detail::tree_node_iterator< container > |
using | const_iterator = detail::tree_node_iterator< container const > |
公開メンバ関数 | |
tree () | |
空のコンテナを構築する | |
tree (allocator_type const &alloc) | |
アロケータを指定して空のコンテナを構築する [詳解] | |
tree (value_type const &value, allocator_type const &alloc=allocator_type()) | |
要素からコンテナを構築する [詳解] | |
tree (value_type &&value, allocator_type const &alloc=allocator_type()) | |
要素からコンテナを構築する [詳解] | |
void | assign (value_type const &value) |
void | assign (value_type &&value) |
allocator_type | get_allocator () const |
reference | front () |
const_reference | front () const |
reference | back () |
const_reference | back () const |
iterator | begin () noexcept |
根を指すイテレータを返す [詳解] | |
const_iterator | begin () const noexcept |
根を指すイテレータを返す [詳解] | |
const_iterator | cbegin () const noexcept |
根を指すイテレータを返す [詳解] | |
iterator | end () noexcept |
根の終端を指すイテレータを返す [詳解] | |
const_iterator | end () const noexcept |
根の終端を指すイテレータを返す [詳解] | |
const_iterator | cend () const noexcept |
根の終端を指すイテレータを返す [詳解] | |
bool | empty () const noexcept |
要素を格納していないことを調べる [詳解] | |
size_type | size () const |
格納している要素数を調べる [詳解] | |
size_type | size (const_iterator pos) const |
部分木が格納するノード数を調べる [詳解] | |
size_type | max_size () const noexcept |
格納可能な要素の最大数を調べる [詳解] | |
void | clear () noexcept |
すべての要素を削除する | |
void | swap (tree &other) |
iterator | insert (const_iterator pos, value_type &&value) |
ノードを挿入する [詳解] | |
iterator | insert (const_iterator pos, value_type const &value) |
要素を挿入する [詳解] | |
iterator | insert (const_iterator pos, const_iterator sub) |
部分木を挿入する [詳解] | |
template<typename... Args> | |
iterator | emplace (const_iterator pos, Args &&... args) |
iterator | move (const_iterator pos, const_iterator sub) |
部分木を移動する [詳解] | |
iterator | erase (const_iterator pos) |
要素を削除する [詳解] | |
限定公開型 | |
using | node_type = detail::tree_node< T > |
using | index_type = typename node_type::index_type |
using | container = std::vector< node_type, Allocator > |
限定公開メンバ関数 | |
index_type | allocate (value_type &&val) |
ノードを確保する [詳解] | |
void | free (index_type idx) |
ノードを解放する [詳解] | |
void | link (index_type parent, index_type pos, index_type idx) |
ノードを木に挿入する [詳解] | |
void | unlink (index_type idx) |
ノードを木から取り除く [詳解] | |
限定公開変数類 | |
container | m_c |
静的限定公開変数類 | |
static constexpr index_type | null_value = node_type::null_value |
フレンド | |
template<typename Container1 > | |
class | detail::tree_node_iterator |
木コンテナ
根以外のノードは一つの親を持つ。 ノードは0あるいはそれ以上の子を持つ。 子を持たないノードを葉と呼ぶ。 ノードは0以上の兄弟を持つ。
この tree 実装は、HTML5 パーサーの要求にこたえるため、複数の根を持つことが可能。
tree において要素間の移動はイテレータを使う。 tree のメンバ関数 begin() で根を指すイテレータを取得する。
イテレータのメンバ関数 parent() で親を取得する。 イテレータのメンバ関数 begin() で先頭の子を取得する。 イテレータのメンバ関数 end() で子の終端を取得する。 イテレータのメンバ関数 operator++() で次の兄弟を取得する。
tree の内部は、一つの配列にすべてのノードが収まっている。 各ノードは、親、子の先頭、前の兄弟、次の兄弟の各インデックスを持つ。 配列のインデックスは 1 から始まる。 根のインデックスは配列の 0 番目の要素の m_child に格納される。
子の先頭の m_prev には最後の兄弟のインデックスを格納する。 先頭の子であることを確認するには、親の m_child と自身が一致するか調べる。
イテレータは、指すノードのインデックスと親のインデックスを保持する。 終端を指すイテレータは、インデックスを 0 として示す。 終端を指すイテレータも(デクリメントで必要となるため)親のインデックスを保持する。 根の親は 0 である。 終端を指すイテレータをデクリメントする場合、親の m_child の m_prev へ 移動する。
配列のインデックス 0 は、ノードとして使用されない。 そのため、未使用ノードの先頭、格納するノード数を保持するのに使う。
未使用ノードは、 m_prev に前の未使用ノード、 m_next に次の未使用ノードの 各インデックスを格納して双方向リンクリストとする。
未使用ノード末尾は、 m_next に 0 を格納して示す。 未使用ノードが一つも無い場合、インデックス 0 の m_next に 0 を格納して示す。
現在の実装は、インデックス順に未使用ノードのリンクが並ぶよう、解放時に整列させる。 この動作によって検索性能が向上するが、解放時間が増える。
|
inlineexplicit |
アロケータを指定して空のコンテナを構築する
[in] | alloc | アロケータ |
|
inlineexplicit |
要素からコンテナを構築する
[in] | value | 根となる要素 |
[in] | alloc | アロケータ |
|
inlineexplicit |
要素からコンテナを構築する
[in] | value | 根となる要素 |
[in] | alloc | アロケータ |
|
inlinenoexcept |
根を指すイテレータを返す
|
inlinenoexcept |
根を指すイテレータを返す
|
inlinenoexcept |
根を指すイテレータを返す
|
inlinenoexcept |
根の終端を指すイテレータを返す
|
inlinenoexcept |
根の終端を指すイテレータを返す
|
inlinenoexcept |
根の終端を指すイテレータを返す
|
inlinenoexcept |
要素を格納していないことを調べる
|
inline |
格納している要素数を調べる
|
inline |
部分木が格納するノード数を調べる
[in] | pos | 部分木の頂点を指すイテレータ |
|
inlinenoexcept |
格納可能な要素の最大数を調べる
|
inline |
ノードを挿入する
[in] | pos | 挿入位置を指すイテレータ |
[in] | value | 挿入する値 |
挿入位置は、引数 pos の前。 子として追加されるのではないことに注意。
|
inline |
要素を挿入する
[in] | pos | 挿入位置を指すイテレータ |
[in] | value | 挿入する値 |
|
inline |
部分木を挿入する
[in] | pos | 挿入位置を指すイテレータ |
[in] | sub | 部分木の根を指すイテレータ |
スタックを使った一般的な木探索アルゴリズムは、木の構造を保持しないため、 POPしたノードを「どこに挿入するか?」という情報を取り出せない。 そこで、挿入地点を記録する「親スタック」を使う。
探索スタックから値をPOPするとき、子が有ればすべて探索スタックにPUSHする。 同時に、親を親スタックにPUSHする。 親スタックにPUSHするとき、スタックTOPが挿入しようとするノードの親であるか検査する。 親でない場合、POPしてからノードをPUSHする。
以上の操作で、親スタックのTOPは常に挿入地点となる。
ところで、以上のアルゴリズムは、引数の部分木について親を記録する。 実際に必要なのは、挿入先の親である。 そこで、親スタックには、挿入先の親も一緒に記録する。
|
inline |
部分木を移動する
[in] | pos | 挿入位置を指すイテレータ |
[in] | sub | 部分木の根を指すイテレータ |
std::invalid_argument | 祖先を子孫へ移動させようとした場合 |
sub を根とする部分木を pos の前へ移動する。 循環するため、祖先を子孫へ移動する事は出来ない。 移動後は親が変わるため、sub は不正なイテレータとなる。 戻り値のイテレータを使うこと。
親をたどって pos から sub に到達できる場合、祖先を子孫へ移動させようとしている。
|
inline |
要素を削除する
[in] | pos | 削除する要素を指すイテレータ |
|
inlineprotected |
ノードを確保する
[in] | val | 格納する値 |
|
inlineprotected |
ノードを解放する
[in] | idx | 解放するノードのインデックス |
|
inlineprotected |
ノードを木に挿入する
[in] | parent | 挿入位置の親のインデックス |
[in] | pos | 挿入位置のインデックス |
[in] | idx | 挿入するノードのインデックス |
挿入するノードは allocate() で得た新規ノード、あるいは unlink() された既存のノード。 挿入するノードは子を持つ部分木であっても、子を持たない単独のノードでも構わない。
idx は、allocate() で取得した新規ノードのインデックス。
parent は、引数 pos から取得する。
child は、 parent の m_child 。
after は、(挿入後にAfterとなるので)挿入位置のインデックス。 end() に挿入する場合、 0 。
before は
インデックス 0 の前に挿入。
根は一つしか無い。 挿入前に格納数は 0 でなければならない。
インデックス 3 の前に挿入。
インデックス 0 の前に挿入。
インデックス 2 の前に挿入。
インデックス 2 の前に挿入。
インデックス 0 の前に挿入。
インデックス 0 の前に挿入。
|
inlineprotected |
ノードを木から取り除く
[in] | idx | 取り除くノード |
この関数で取り除いたノードは木の中に無く、解放もされていない。 取り除いた後、どこかに挿入するか、解放する必要が有る。