データ構造とアルゴリズム
第五回 (2009年11月
6日)
分割統治法、マージソート
http://www.sw.it.aoyama.ac.jp/2009/DA/lecture5.html
Martin J. Dürst
© 2008-09Martin
J. Dürst 青山学院大学
目次
- 前回のまとめ・演習・宿題
- 整列の重要性
- 単純な整列法
- Ruby の繰返し
- 分割統治法
- マージソート
前回のまとめ
- 順位キューは大事な抽象データ型
- 配列や連結リストによる実装は効率悪い
- ヒープでは最優先の項目が完全二分木の根に出現
- ヒープソートによって整列が可能
前回からの宿題
- ヒープの合併を実装しなさい
- 小さい方のヒープの項目を大きい方に追加
- 二項ヒープ (binomial heap)
- 情報テクノロジーでの整列 (sort)
の応用を五つ考えなさい
整列の重要性
- 出力の様々な整理
- 検索 (例: 二分探索) の前提
- アルゴリズムの部品
単純な整列方法
- バブル整列法 (bubble sort)
- 選択整列法 (selection sort)
- 挿入整列法 (insertion sort)
Ruby の様々な繰返し
一定数の繰返し
構文:
回数.times do
# 何かの作業
end
応用例:
(length-1).times do
# bubble
end
添字を使った繰返し
構文:
出発値.upto 目的値 do |添字変数|
# 添字を使った作業
end
応用例:
sum = 0
1.upto 100 do |i|
sum += i
end
バブル整列法
(bubble sort)
- 隣接の項目を比較、交換
- 配列の先頭から最後までで一つのパス
- 必要なパスの数が n-1
- 計算量は O(n2)
改良:
- 交代で両方向にバブル
- 最後の交換点を記憶、交換のチェックの範囲を限定
選択整列法
(selection sort)
- 配列の先頭に整列済みの部分を徐々に拡大
- 整列済みでない最小の項目を繰返し検索、選択
- 整列済みの部分の直後の項目と最小の項目を交換
- 交換の回数は O(n)
- 比較の回数と全体の計算量は O(n2)
挿入整列法
(insertion sort)
- 配列の先頭に整列済みの部分を徐々に拡大
- 整列済みの部分の直後の項目の場所を整列済みの部分に探す
- 場所を空けるために整列済みの項目の一部をずらす
- 計算量は (最悪で) O(n2)
- 既に殆ど整列されたデータの場合に有利
改良: 番兵 (sentinel) の使用:
最初の項目の前に全ての項目より小さいものを設置
分割統治法
(divide and conquer, ラテン語: divide et impera)
- 軍事戦略や戦術の用語
- 一つの大問題を複数の小問題に分割
- プログラミング一般の大事な原則
- アルゴリズムやデータ構造の一つの設計方針
マージソート
(merge sort)
- 整列対処項目を再帰的に二分割
- 項目数が一つの場合、整列済み
- 分割した両部分が整列出来たら、併合 (merge) で統合
併合
(merge)
- 2 ウェイ併合 (two-way merge) とマルチウェイ併合 (multi-way
merge)
- 二以上の整列済みの列から一つの整列済みの列を作成
- 入力の列のどちらか小さい方の項目を次々と選択
- 最後にどちらかの列の項目が残るのでコピー
マージソートの計算量
整列の計算量
- 単純な整列法以外、整列の計算量は O(n log n)
が多い
- 整列では比較と移動が基本操作
- n 個のデータの場合、異なる順番は n!
- 一つの比較では異なる順番を最大で半分に減らされる
- 最低の比較の数が log (n!) ≈ O(n
log n)
マージソートの特長
- メモリが二倍必要
- 内部より外部メモリに最適
- 外部メモリ:
- パンチカード
- 磁気テープ
- ハードディスクのファイル
次回のための準備
- 前回と今回の整列法の計算量を線形探索で使った方法で調べなさい