情報工学概論 (アルゴリズムとデータ構造)

Slides:



Advertisements
Similar presentations
組合せ最適化輪講 2.3 連結性 川原 純. 2.3 連結性 内容 – グラフ上の節点をすべてたどるアルゴリズム 計算機上でのグラフの表現 – 強連結成分を求めるアルゴリズム トポロジカル順序を求める方法も – k- 連結、 k- 辺連結について – 2- 連結グラフの耳分解について.
Advertisements

A Simple Constant Time Enumeration Algorithm for Free Trees 中野 眞一 宇野 毅明 群馬大学 情報学研究所 2003 年 9 月 19 日 アルゴリズム研究会.
区間グラフにおける区間表現からMPQ-treeを効率よく構成するアルゴリズム
4.3 マージソート.
離散システム特論 整列(sorting)アルゴリズム 2.
アルゴリズムイントロダクション第2章 主にソートに関して
2 分探索木 Binary Search Tree 実行可能な操作 計算量 木の高さは,最悪 O(n) n = |A| : 要素の個数
アルゴリズムとデータ構造 第8回 ソート(3).
近似アルゴリズム 第10章 終了時刻最小化スケジューリング
第11回 整列 ~ シェルソート,クイックソート ~
アルゴリズムとデータ構造 2013年6月18日
アルゴリズムとデータ構造1 2005年7月8日
アルゴリズムとデータ構造 2010年7月5日
算法数理工学 第1回 定兼 邦彦.
4-3:高度なソートアルゴリズム① (分割統治法にもとづくソート)
情報工学概論 (アルゴリズムとデータ構造)
第10回 ソート(1):単純なソートアルゴリズム
JAG Regional Practice Contest 2012 問題C: Median Tree
アルゴリズムとデータ構造 2012年6月14日
情報工学概論 (アルゴリズムとデータ構造)
東京大学大学院情報理工学系研究科 数理情報学専攻 定兼 邦彦 2016年4月7日
岩井 儀雄 コンピュータ基礎演習  ー探索、整列ー 岩井 儀雄
データ構造と アルゴリズム 第八回 知能情報学部 新田直也.
アルゴリズムとデータ構造 2011年6月14日
アルゴリズムとデータ構造 第7回探索のためのデータ構造(1) 2015/11/18 アルゴリズムとデータ構造 2015.
第11回 整列 ~ シェルソート,クイックソート ~
算法数理工学 第1回 定兼 邦彦.
二分探索木によるサーチ.
7-3.高度な木 (平衡木) AVL木 平衡2分木。回転操作に基づくバランス回復機構により平衡を保つ。 B木
算法数理工学 第3回 定兼 邦彦.
アルゴリズムとデータ構造 2012年6月28日
アルゴリズムとデータ構造 2011年6月27日
第25章 単一始点最短路 3節 Bellman-Fordのアルゴリズム
定兼邦彦 今井浩 東京大学理学系研究科 情報科学専攻
アルゴリズムとデータ構造1 2006年7月4日
アルゴリズムとデータ構造1 2006年6月16日
情報工学概論 (アルゴリズムとデータ構造)
ソートアルゴリズムの種類 選択ソート (selection sort) バブルソート (bubble sort)
アルゴリズムとデータ構造勉強会 第6回 スレッド木
情報工学概論 (アルゴリズムとデータ構造)
アルゴリズムとデータ構造 第3章 ヒープ 6月10日分
第9回 優先度つき待ち行列,ヒープ,二分探索木
クイックソート.
大岩 元 慶応大学環境情報学部 再帰 データ構造とプログラミング(8) 大岩 元 慶応大学環境情報学部
データ構造と アルゴリズム 第七回 知能情報学部 新田直也.
基本情報技術概論(第6回) 埼玉大学 理工学研究科 堀山 貴史
Cプログラミング演習 第10回 二分探索木.
アルゴリズムとプログラミング (Algorithms and Programming)
先進的計算基盤システムシンポジウム SACSIS2007併設企画 マルチコアプログラミングコンテスト 「Cellスピードチャレンジ2007」
プログラミング 4 整列アルゴリズム.
プログラミング 4 探索と計算量.
プログラミング 4 木構造とヒープ.
15.cons と種々のデータ構造.
算法数理工学 第7回 定兼 邦彦.
アルゴリズムとデータ構造 第3章 ヒープ 5月31日分の復習
データ構造とアルゴリズム (第5回) 静岡大学工学部 安藤和敏
AVL木.
第9回 優先度つき待ち行列,ヒープ,二分探索木
算法数理工学 第4回 定兼 邦彦.
アルゴリズムとデータ構造 2013年7月1日
基本情報技術概論(第6回) 埼玉大学 理工学研究科 堀山 貴史
情報工学概論 (アルゴリズムとデータ構造)
Advanced Data Structure 第3回
アルゴリズムとデータ構造1 2009年7月2日
ソートのプログラムの流れ 配列の中身を小さい順に並び替える a[1],a[2],…a[n]の値を順に出力する
平面走査法を使った 一般線分の 交点列挙アルゴリズム
ヒープソート.
参考:大きい要素の処理.
7.木構造 7-1.データ構造としての木 7-2.2分探索木 7-3.高度な木.
Ibaraki Univ. Dept of Electrical & Electronic Eng.
Presentation transcript:

情報工学概論 (アルゴリズムとデータ構造) 第9回

14. データ構造の補強 新しいデータ構造が必要なときでも,標準的なデータ構造に情報を追加することで十分な場合が多い 2色木を拡張する 動的集合での順序統計量の計算 区間の動的集合の管理

14.1 動的順序統計量 n 個の要素からなる集合の i 番目の順序統計量: 集合の中で i 番目に小さいキーを持つ要素 任意の順序統計量は O(n) 時間で求まる 2色木を補強して,任意の順序統計量を O(log n) 時間で決定できるようにする. 要素のランク (rank) (指定された要素が小さい方から何番目か) も O(log n) 時間で求まる

順序統計量木 各ノード x は部分木のサイズ size(x) を 格納するフィールドを持つ 26 12 17 7 41 7 14 4 21 5 30 1 47 4 10 2 16 2 19 1 23 1 28 3 38 2 7 1 12 1 15 1 20 1 35 1 39 1 3 各ノード x は部分木のサイズ size(x) を 格納するフィールドを持つ size(x) = size(left(x)) + size(right(x)) + 1

与えられたランクを持つ要素を求める OS_SELECT(x, i): x を根とする部分木で i 番目に小さいキー (順序統計量) を持つ節点を返す size(left(x)) + 1はxを根とする部分木でのxのランク 計算量: O(lg n) node OS_SELECT(node x, int i) { int r; r = size(left(x)) + 1; if (i == r) return x; else if (i < r) return OS_SELECT(left(x),i); else return OS_SELECT(right(x), i-r); }

OS_SELECT(root(T), 17) の場合 20 i = 17 > 12+1 26 12 17 7 41 i = 4 < 5+1 1 7 14 4 21 5 30 47 i = 4 > 1+1 4 10 2 16 2 19 1 23 1 28 3 38 i = 2 = 1+1 2 7 1 12 1 15 1 20 1 35 1 39 1 3

要素のランクを求める 節点 x のポインタが与えられたときに,その要素が小さい方から何番目かを返す 計算量: O(lg n) int OS_RANK(tree T, node x) { int r; node y; r = size(left(x)) + 1; // r を根とする部分木での x のランク y = x; while (y != root(T)) { if (y == right(p(y))) r += size(left(p(y)) + 1; y = p(y); } return r;

OS_RANK(T, x) の例 r = r + 12+1 = 17 20 26 12 17 7 41 r = r +1+1 = 4 1 7 14 4 21 5 30 47 1 x r = 1+1 4 10 2 16 2 19 1 23 28 3 38 1 2 7 1 12 1 15 1 20 35 1 39 1 3

部分木のサイズの管理 2色木の形状が変化すると size フィールドの値は変化する 挿入,削除後も size の値を維持できることを示す 挿入の場合 木を根から辿り新しい要素を挿入する場所を見つける 新しい要素の祖先の size を1ずつ増やす 2色木の回転操作を行う size を調整する

size(x) = size(left(x)) + size(right(x)) + 1 y 19 x 19 RIGHT_ROTATE(T,x) 42 93 x y 93 12 11 42 7 7 6 4 6 4 size(y) = size(x) size(x) = size(left(x)) + size(right(x)) + 1 1回の回転は O(1) 時間 回転は高々2回 全体の計算量: O(lg n)

削除の場合 ノード y を削除したあとに size が変化する節点は,y の祖先のみ 回転操作は挿入と同様 高々3回の回転 計算量: O(lg n)

14.2 データ構造の補強 元になるデータ構造を選ぶ 元になるデータ構造で追加情報として管理されるものを決定する 2色木 元になるデータ構造で追加情報として管理されるものを決定する 部分木のサイズ size 元になるデータ構造の基本操作に対して追加情報を維持できることを確認する 挿入,削除時の size の更新が O(lg n) 時間 新しい操作を開発する OS_SELECT, OS_RANK

定理15.1 (2色木の補強) T を n 節点からなる2色木, f を T を補強するフィールドとする.節点 x に対する f の内容は x の情報 (left(x), right(x), f(left(x), f(right(x)) のみを用いて計算できるとする. このとき,挿入/削除の際に T の全ての節点の f の 値を O(lg n) 時間で維持できる. 証明: (アイデア) f の内容はその子供から決まる. よってある節点 x での f の変更はその祖先にしか 影響を与えない.よって挿入/削除の際の f の更新は O(lg n) 時間.

挿入の場合: 第1段階: 新しい節点 xは既存の節点の子として挿入. x の子は共にNILなので f(x) は O(1) 時間で計算可. x の祖先の節点での f の更新は O(lg n) 時間. 第2段階: 木構造の変化は回転によってのみ発生. 1つの回転では2つの節点のみが変化する. 節点が1つ変化するたびにその節点とその先祖の f を更新する.その時間は O(lg n). 挿入の際に発生する回転は高々2回であるため, 挿入に要する総時間は O(lg n). 削除も同様.

注:多くの場合,回転後の更新のコストは O(lg n) ではなく O(1). x RIGHT_ROTATE(T,y) 19 y 19 42 93 y x 93 12 11 42 7 7 6 4 6 4 size(y) = size(x) size(x) = size(left(x)) + size(right(x)) + 1

14.3 区間木 定義: 閉区間 (closed interval) とは,実数の順序対 [t1, t2] (t1  t2) 開区間(open interval),半開区間(half-open interval) は区間の短点の両方または片方を省いたもの ここでは閉区間のみを扱う 区間木は,ある与えられた期間に起こった出来事を見つける質問などに用いられる

区間の間の関係 区間 [t1, t2] をオブジェクト i とする. i はフィールド low[i] = t1 (下端点),         high[i] = t2 (上端点) で表される 区間 i と i’ が重なる  i  i’   つまり 1. low[i]  high[i’] かつ low[i’]  high[i] 区間 i と i’ が重ならない場合 2. high[i] < low[i’] または 3. high[i’] < low[i] i i i i i’ i’ i’ i’ i i’ i’ i

区間木での操作 木の各要素は区間 Int(x) を持つ INTERVAL_INSERT(tree T, node x): x を挿入 INTERVAL_DELETE(tree T, node x): x を削除 INTERVAL_SEARCH(tree T, interval i): Int(x) が区間 i と重なっている要素 x のポインタを返す 1. 元になるデータ構造: 2色木 各節点 x は区間 Int(x) を含む x のキーは区間の下端点 low(Int(x))

19 20 8 9 26 26 17 19 6 10 25 30 5 8 16 21 3 15 23 [16,21] 30 Int [8,9] 23 [25,30] 30 Max [5,8] 10 [15,23] 23 [17,19] 20 [26,26] 26 [0,3] 3 [6,10] 10 [19,20] 20 Max(x): x を根とする部分木に蓄えられている区間の 端点の最大値 (つまり上端点の最大値)

2. 追加情報 Int(x): 区間 Max(x): x を根とする部分木に蓄えられている区間の端点の最大値 (つまり上端点の最大値) 3. 情報の更新 挿入/削除を行なったときに Max が O(lg n) 時間で更新できることを示す Max(x) = max{high(Int(x)), Max(left(x)), Max(right(x))} より,O(lg n) 時間で更新できる

4. 新しい操作の実装 区間 i と重なっている区間を見つける O(lg n) 時間 node INTERVAL_SEARCH(tree T, interval i) { node x; x = root(T); while ((x != NIL) && (high(i) < low(int(x)) || high(int(x)) < low(i))) { // i と int(x) が重ならない if (left(x) != NIL && Max(left(x)) >= low(i)) x = left(x); else x = right(x); } return x;

i = [22,25] Max(left(x))  low(i) 23  22 [16,21] 30 [8,9] 23 [25,30] 30 10 < 22 [5,8] 10 [15,23] 23 [17,19] 20 [26,26] 26 [0,3] 3 [6,10] 10 i と重なりを もつので出力 [19,20] 20

i = [11,14] 右の部分木のどの区間も i とは重ならない 23  11 [16,21] 30 左の部分木は i とは重ならない [8,9] 23 [25,30] 30 10 < 11 [5,8] 10 [15,23] 23 [17,19] 20 [26,26] 26 [0,3] 3 [6,10] 10 [19,20] 20 右の子はNILなので NILを出力

定理 15.2 INTERVAL_SEARCH(T, i) の実行中の whileループにて, 1. 探索が左に行ったとき: x の左部分木は i と重なり合う区間を含むか,x の右部分木のどの区間も i とは重ならない 2.探索が右に行ったとき: x の左部分木のどの区間も i とは重ならない 証明: 2の場合: 右に行く場合は left(x) = NIL または Max(left(x)) < low(i) が成り立つ. 前者の場合は x の左部分木は空であるので成立.

後者の場合, i’ を x の左部分木内の区間とする. Max(left(x))は x の左部分木中の最大の端点なので low(i)

1の場合: x の左部分木中の区間で i と重なり合う ものが見つかれば探索は終了する. 見つからない場合に,x の右部分木中のどの 分岐の条件より, Max(left(x))  low(i). Maxの定義より,x の左部分木中にある区間 i’ が 存在して i と i’ は重ならないため i i’ low(i) Max(left(x))

キーは区間の下端点であり,探索木の性質から, x の右部分木中のどの区間 i’’ に対しても が成り立つ.つまり となり,i と i’’ は重ならない. この定理から,ある方向に探索して区間が見つか らなかった場合は反対側にも解がないことが保障 される. i’’ i i’ low(i) Max(left(x))

問合せと交わる区間を全て出力 void interval_search_enumerate(tree *T, node *x, interval i) { if (x == nil(T)) return; if (low(i) > Max(x)) return; // i の下端点が, x を根とする部分木内の区間の上端点より //大きいなら部分木内の全ての区間は i と交わらない if (left(x) != nil(T)) interval_search_enumerate(T, left(x), i); if (low(i) <= high(Int(x)) && low(Int(x)) <= high(i)) { // 交わっていれば表示 printf("[%lf,%lf]\n", low(Int(x)), high(Int(x))); } if (high(i) < low(Int(x))) return; // i の上端点が, x を根とする部分木内の区間の下端点より //小さいなら, 右部分木内の全ての区間は i と交わらない if (right(x) != nil(T)) interval_search_enumerate(T, right(x), i);

10. 中央値と順序統計量 n 要素の集合の i 番目の順序統計量 (order statistic): その集合で i 番目に小さい要素 最小値 (minimum): i = 1 最大値 (maximum): i = n 中央値 (median): n が奇数のとき i = (n+1)/2 n が偶数のとき いずれの場合も

選択問題 (selection problem) 入力: n 個の異なる数の集合 A, 整数 i (1  i  n) 出力: A 中のちょうど i 1 個の他の要素より大きい要素 x  A 選択問題は O(n lg n) 時間で解ける A の要素をソートする 出力配列の i 番目の要素を返す 選択問題は O(n) 時間で解ける

10.2 平均線形時間の選択法 順序統計量は (n) 時間で求まるが複雑 まず,平均的に O(n) 時間のアルゴリズムを考える data RANDOMIZED_SELECT(data *A, int p, int r, int i) // A[p..r] の中で i 番目に小さい要素を返す { int q, k; if (p == r) return A[p]; q = RANDOMIZED_PARTITION(A,p,r); // q: 分割の位置 k = q – p + 1; // k: 左部分の要素数 if (i <= k) return RANDOMIZED_SELECT(A,p,q,i); else return RANDOMIZED_SELECT(A,q+1,r,ik); }

q = RANDOMIZED_PARTITION(A,p,r);の実行後 2つの空でない部分配列 A[p..q], A[q+1..r] に分かれる 左側の各要素は右側よりも小さい k = q – p + 1; は左側の要素数 i  k ならば i 番目の要素は左側の i 番目 i  k ならば i 番目の要素は右側の i  k 番目 部分配列のサイズが 1 になるまで繰り返す

平均実行時間の上界 T(n): n 要素の集合での選択問題の平均時間 分割の左側のサイズが T(n) は単調増加と仮定する i になる確率 = 1/n (i = 2,3,...,n1) T(n) は単調増加と仮定する

RANDOMIZED_SELECTの最悪実行時間は(n2)よって 1/n T(n1) = O(n) T(n)  cn と仮定すると

10.3 最悪線形時間の 選択アルゴリズム アルゴリズム SELECT: i 番目に小さい要素を返す 入力配列の n 要素をグループに分割 n mod 5 要素のグループ 高々1個 n/5 個の各グループを(挿入ソート等で)ソートし,それぞれの中央値を求める SELECTを再帰的に用いてステップ2で求めた n/5 個の値の中央値 x を求める

PARTITIONを修正したものを用い,入力配列を x によって分割する.左側の要素数を k とする. i  k ならば,左側で i 番目に小さい要素を再帰的に見つける. i  k ならば,右側で ik 番目に小さい要素を再帰的に見つける.

SELECTの実行時間の解析 分割に用いた x より大きい要素数の下界を求める 中央値が x 以上のグループには,x 以上の値が 3個以上ある x 以上となる要素数は少なくとも

同様に,x 以下となる要素数も少なくとも 3n/106 ステップ 5 で再帰的に呼ばれる SELECT の部分問題のサイズは高々 7n/10+6 ステップ 1,4: O(n) 時間 ステップ 2: 5 要素のソートを n/5 回⇒ O(n)時間 ステップ 3: T(n/5) 時間

n  80 に対して T(n)  cn と仮定する.    c を十分大きくとれば よって,SELECTの最悪実行時間は線形 これは比較しか用いていない

クイックソートの pivot として厳密な中央値を用いれば,最悪計算量が O(n log n) になる ただし,SELECTが複雑なので実行速度は 速くない また,in-placeではなくなる