データ構造とアルゴリズム
第八回
(2013年11月22日)
辞書とその実装: 二分木など
http://www.sw.it.aoyama.ac.jp/2013/DA/lecture8.html
Martin J. Dürst
© 2009-13 Martin
J. Dürst 青山学院大学
目次
- 前回の残り・まとめ
- O(n log n) より早い整列法
- 辞書
- 二分木とその辿り方
- 二分探索木
- 平衡木
前回の残り
前回のまとめ
- クイックソートは効率のよい整列法
- 最悪の場合に O(n2); 平均で
O(n log n)
- 分割要素の選択など実装で注意点が多い
- 実装例: 7qsort.rb
- 様々な整列法のアニメーション: sort.svg
レポートについて
「失敗」の例:
[都合により削除]
O(n log n) より早い整列法
- 今までの整列法は値の任意な分布に対応
- 比較の決定木で最低 O(n log n)
- 値の分布について前知識がある場合、改善可能
- 極端な例: 1 から n までの数の整理
→最終的な場所が完全に予想可能
→O(n)
- 基数整列 (radix sort)、
ビンソート (bin sort, bucket sort) など
ビンソート
例: 学生番号で整列
- 最上位の桁で 10 の山に分割
- 各々の山を再帰的に順に下位の桁で分割
- 山の大きさに対応するため、分割を二つのフェーズで実行
- 各々の山の大きさを計算
- 要素の再配置
- 計算量は O(n
k) (k は桁の数)
基数整列
- 最下位の桁から
- 上位の桁で分割する必要がない
- 安定な整列法が必要
- 計算量は O(n
k) (k は桁の数)
辞書の抽象データ型
(dictionary; 注: 実際の辞書とは違う)
- データ項目ごと
- キー (key): 項目の特定のため、探索に使用
- 値 (value): キー以外の項目ごとの情報、無しも可
- 操作
- 挿入 (insert)
- 削除 (delete)
- 探索 (search/find)
辞書の簡単な実装
- 整列済の配列: 探索は二分探索で O(log
n)、挿入・削除は O(n)
- 未整列の配列、連結リスト: 探索は O(n)
- 挿入・削除・探索を全て O(log
n) 以内で実装したい
二分木
- グラフ (graph): 頂点 (ノード、node) と辺 (edge)
からなる
- 木 (tree): 根 (root) は親 (parent)
が無いが、他の頂点が全て一つの親とつながっている
- 二分木 (binary tree): 各頂点に子 (child) が最大 2 個
二分木の辿り方
- 深さ優先 (depth first)
- 行きがけ順 (preorder)
- 通りがけ順 (inorder)
- 帰りがけ順 (postorder)
- 幅優先 (breadth first)
二分探索木
- 各頂点にデータ項目を一つ配置
- 任意の頂点のキーが k の場合
- 左の部分木のキーが k より小さい
- 右の部分木のキーが k より大きい
- 同等なキーが複数ある場合の扱いは実装依存
探索木での探索
- 根から探索を開始
- 現在の頂点のキーと比べ探索のキーが
- 同じ: 頂点のデータ項目を返す
- 小さい: 左の部分木を探索
- 大きい: 右の部分木を探索
- 空の頂点: 探索終了
探索木への挿入
- 根から挿入を開始
- 現在の頂点のキーより挿入のキーが
- 小さい: 左の部分木に挿入
- 大きい: 右の部分木に挿入
- 空の頂点: 挿入の頂点に置換 (その子は空の頂点)
- 同じ: 挿入打ち切り、右の部分木に挿入、など
探索木からの削除
- 削除したい頂点を発見 (探索参照)
- 削除したい頂点に (真の) 子が
- ない: そのまま削除
- 一個だけ: それと置換
- 二個: 右の部分木の一番小さいキーの頂点と置換
探索木の実装
- 子が無い場所、特殊なノード (
NilNode
)
を全てのノードで共有
- Ruby での実装: 8bintree.rb
単純な探索木の評価
- 木全体の高さで操作の計算時間が決まる
- 最善の高さが O(log
n)
- 最悪の高さが O(n)
- 平均の高さが O(log
n)
平衡木
(balanced tree)
- 一般の探索木は最悪、連結リストの形を同等
- 挿入・削除の順番が決まっているため、
(クイックソートのように)
乱数などで分割項目を決めることは不可能
- 完全二分木の場合、追加・削除の手間が課題
解決策: 完全ではないがある程度平衡性を保つ木
トップダウン 2-3-4 木
(top-down 2-3-4 tree)
- 各ノードの子数は 2、3 または 4
- 子数が k の場合、ノードに k-1
のキーとデータ項目を保持
(子数が全て 2 の場合、二分探索木と同等)
- ノード内のデータ項目のキーは部分木の分岐点
- 木の高さは一定
- 一番下の層には子がない
(実装上、全部同一の空のノード)
次回への宿題
(提出無し)
- データ項目が n
の場合の最低と最大の木の深さを考える
- 2-3-4
木の追加の操作を複数の例を使って考えて、アルゴリズムを提案