ITパスポート試験 用語辞典

きこうぞう
木構造
コンピュータのデータ構造の1つで、1つの根から複数のデータに枝分かれした状態で配置された構造。各階層は親子関係を持っており、親は複数の子を持ち、その子は自分を親として複数の子を持つことができるが、子は複数の親を持つことがない。
木が幹から枝、枝から葉に分岐していく様子に似ているためこう呼ばれる。

木構造を構成する要素は「node(節)」といい、すべてのデータにとって上位に位置した(親を持たない)最上位の階層は「root(根)」という。
ファイルシステムにおけるディレクトリなどは、木構造によって管理されているといえる。

なお、木構造の中でも、枝分かれが必ず2つだけ存在しているものはバイナリツリー(完全二分木)、子の数がN個に制限されている木をN分木という。
↓ 用語データを見る
分野:
分野:テクノロジ系
中分類:アルゴリズムとプログラミング
小分類:データ構造
重要度:
(Wikipedia 木構造 (データ構造)より)

木構造(きこうぞう)とは、グラフ理論の木の構造をしたデータ構造のこと。

用語

木構造は、ノード(節点、頂点)とノード間を結ぶエッジ(枝、辺)あるいはリンクで表される。

データ構造として使われる木は、ほとんどの場合、根となるノードが決められた根付き木で、ノード間の関係は家系図に見立てた用語で表現される。木構造内の各ノードは、0個以上の子ノード (child node) を持ち、子ノードは木構造内では下方に存在する(木構造の成長方向は下とするのが一般的である)。子ノードを持つノードは、子ノードから見れば親ノード (parent node) である。あるノードから見て、同じ親を持つノードを兄弟ノード (sibling node) という。あるノードから見て、その子ノードやそこから先の子ノード全てのいずれかを子孫ノード (descendant node) と呼び、その親ノードやそこから先の親ノードの全てのいずれかを先祖ノード (ancestor node) と呼ぶ。ノードは高々1個の親ノードを持つ。

根ノード (root node) とは、親ノードを持たないノードのこと。根ノードは木構造の最上位にあるノードであり、1つの木構造に高々1つしか存在しない。根ノードからスタートして、親から子へ、またその子へ、とエッジを辿っていくと、あらゆるノードへ必ず到達でき、そのような(根から特定ノードまでの)経路は常に一意である。図で示す場合、根ノードが一番上に描かれるのが普通である。二分ヒープなどの木構造では、根ノードは特別な属性を持つ。木構造内の全てのノードは、そのノードを頂点とする部分木の根ノードと見なすことができる。

葉ノード (leaf node) とは、子ノードを持たないノードのこと。葉ノードは木構造の下位の末端にあるノードであり、ひとつの木に複数存在しうる。

内部ノード (internal node、inner node) とは、子ノードを持つノード、すなわち葉ノード以外のノードのこと。

高さ (height) とは、あるノードについて、そのノードからその子孫である葉ノードへのエッジ数の最大値のこと。
根ノードの高さはその木構造の高さである。

深さ (depth) とは、逆に、あるノードについて、そのノードから根ノードまでのエッジ数のこと。根ノードの深さは 0 である。

部分木 (subtree) は、木構造の一部であり、それ自身も完全な木構造となっている部分を指す。木構造 T の任意のノードは、その配下の全ノードと共に T の部分木を構成する。根ノードを頂点とする部分木は、その木構造全体と等しい。根ノード以外を頂点とする部分木は真部分木 (proper subtree) と呼ばれる(部分集合と真部分集合とのアナロジー)。

(forest) とは、木の集合のこと。グラフ理論では、森は閉路をもたない(連結とは限らない)グラフである。
森が順序木の順序集合である場合、これを木の木と考えることで前順、間順、後順の走査法を再帰的に定義できる。

木構造における順序性

木構造は2種類に分類される。順序性のない木と、順序性のある木である。順序性のない木は、構造的には木だが、あるノードの子ノード群には順序が存在しない。順序性のある木では、子ノードをリストに入れたり、各エッジ(枝)に異なる自然数を付与するなどして子ノード間に順序性をつける。これを順序木 (ordered tree) と呼ぶ。一般に実際に使われるデータ構造としては順序木の方が典型的である。2分探索木は順序木の一種である。

実装方法

コンピュータで利用する場合にはいくつかの実装方法がある。典型的な実装としては、動的メモリ確保でノードを表す構造体の領域を確保し、で親ノードや子ノードを参照できるようにする。
  • 各ノードが子ノードへのポインタのリストを持つ
  • 各ノードが親ノードへのポインタを持つ
  • 各ノードが親ノードへのポインタと子ノードへのポインタのリストを持つ
  • 各ノードが長男ノードへのポインタと弟ノードへのポインタを持つ

他にも、配列を使った実装(ポインタではなく、インデックスによって親子関係が決定される)などがある(例えば、二分ヒープ)。

グラフとしての木構造

グラフ理論では、木とは非環状(ループを持たない)グラフを意味する。根付き木は、根として選ばれたノードを持つグラフである。この場合、エッジでつながれた2つのノードには親子関係が成り立つ。

走査法

木構造の走査 (traverse) とは、木構造にある全ノードを一回ずつ体系的に調査する処理である。連結リストや1次元の配列のような線形性のあるデータ構造では、走査は普通は前から順番に行われる(後ろからたどる方法などもある)。木構造の走査には下記の方法などがある。以下のアルゴリズムは二分木に関するものだが、多分木にも応用可能である。

深さ優先探索

現在のノードを調査し、その子ノードに対して同じことを繰り返す。従って、再帰呼び出しで容易に表現できる(ループでも実装可能)。走査法は、ノードを調査する順序によって以下の3つに分類される(いずれの方法も、根から探索を開始する)。

前順・先行順・前置順・行きがけ順 (pre-order)
根ノードを調査する。
もしあれば、左の部分木を前順走査する。
もしあれば、右の部分木を前順走査する。
2分探索木のコピーを作る際によく利用される。また、数式の構文木からーランド記法の表現を得るのにも利用される。
間順・中間順・通りがけ順 (in-order)
もしあれば、左の部分木を間順走査する。
根ノードを調査する。
もしあれば、右の部分木を間順走査する。
多分木では定義されない。2分探索木では、間順走査によって走査する順がソートされた順序になるため、よく使われる。
後順・後行順・後置順・帰りがけ順 (post-order)
もしあれば、左の部分木を後順走査する。
もしあれば、右の部分木を後順走査する。
根ノードを走査する。

幅優先探索

レベル順 (level-order)
深さが同じノードを浅い方から順に走査していく。

走査例

102.png
この2分探索木において、
  • 前順走査での調査順: F, B, A, D, C, E, G, I, H
  • 間順走査での調査順: A, B, C, D, E, F, G, H, I
    • 2分探索木での間順走査は、ソートされた順となる。
  • 後順走査での調査順: A, C, E, D, B, H, I, G, F
  • レベル順走査での調査順: F, B, G, A, D, I, C, E, H

擬似コード

前順(n)
n を処理
for each (n の子ノード i)
前順(i)
間順(n)
if (n に左の子ノードがあれば)
間順(n の左の子ノード)
n を処理
if (n に右の子ノードがあれば)
間順(n の右の子ノード)
後順(n)
for each (n の子ノード i)
後順(i)
n を処理

これらの実装では、木構造の高さのぶんだけコールスタック領域を必要とする。平衡が保たれていない木では、これが深刻な問題となる場合もある。各ノードの親ノードの位置を覚えておくことでスタックを使わないようにもできる。

下記はレベル順の擬似コード。

レベル順(n)
n をキューに追加
while (キューに要素を含むなら)
n ← キューから取り出す
n を処理
for each (n の子ノード i)
i をキューに追加

糸付き2分木

また、 糸付き2分木(threaded binary tree) を使う方法もある。Joseph M. Morris が1979年に発表した。糸付き2分木は、子ノードがない場合に間順の前と後ろをそれぞれ左の子ポインタと右の子ポインタに設定しておいた木構造である。この場合、子ノードの有無はポインタ以外のフィールドで示す必要がある。これを使うと、間順走査の効率が非常によくなるが、前順や後順は通常のスタックを使った実装の方がよい。

糸付き2分木を間順走査するコードは次のようになる。

Sub inorder(n∈node)
    Do While hasLeftChild(n)
        Let node ← node.left
    Loop
    Do
        visit(n)
        If hasRightChild(n) Then
            Let n ← n.right
            Do While hasLeftChild(n)
                Let n ← n.left
            Loop
        Else
            Let n ← n.right
        End If
    Loop While n ≠ Null
End Sub

主な操作

  • アイテム(データを持つノード)数を数え上げる。
  • あるアイテムを探索する。
  • 新たなアイテムを木構造の特定の位置に追加する。
  • アイテムを削除する。
  • 部分木を削除する(枝刈り)
  • 部分木を追加する(接ぎ木)
  • 任意のノードから根ノードを探す。

木構造の種類

  • 子ノード数での分類
    • 二分木 - 各ノードが子ノードを最大2つしかもたない木
      • 2分探索木
    • 多分木 - 子ノードを3つ以上持つノードを含む木。二分木でない木
      • 四分木
      • 八分木
  • 平衡木(バランス木) - すべての葉について、深さがほぼ等しい木
    • 平衡2分探索木 - 平衡木であり、同時に2分探索木でもある木
      • AA木
      • AVL木(一般に平衡2分木と呼ばれるが、平衡2分探索木と紛らわしいので注意)
      • スケープゴート木
      • 赤黒木(2色木)
      • T木 (T-tree)
      • スプレー木 (splay tree)
      • Treap
    • 多分木
      • B木 (B-tree)
        • B+木、B*木
      • 2-3木、2-3-4木
  • ヒープ
    • 二分ヒープ(バイナリヒープ)
    • 二項ヒープ
    • フィボナッチヒープ
  • デジタル木 - 主に文字列の格納のためにつかわれる木
    • トライ木
    • パトリシア木(基数木)
    • 接尾辞木 (Suffix tree)
  • その他
    • 領域探索木 (range tree)
    • 区分木 (segment tree)
    • 区間木 (interval tree)
    • R木 (Rectangle tree)
    • kd木

コンピュータにみる木構造

木構造は主に以下のような用途で使われる
  • 階層構造のあるデータを操作する。ディレクトリツリー、ドメイン名、構文木、制御構造、決定木、XML DOMツリーなど。
  • 情報を探索しやすくする。データベースのインデックス など。この用途の木構造を探索木とも呼ぶ。
  • データのソートのために使用する。ヒープソートなど。

「データ構造」の用語

「アルゴリズムとプログラミング」の他の分野

「テクノロジ系」の他のカテゴリ

このページのWikipediaよりの記事は、ウィキペディアの「木構造 (データ構造)」(改訂履歴)の記事を複製、再配布したものにあたり、このページ内の該当部分はクリエイティブ・コモンズ 表示 - 継承 3.0 非移植 ライセンスの下 に提供されています。


Pagetop