420 likes | 782 Views
情報システム基盤学 基礎 1 アルゴリズムとデータ構造. Elements of Information Systems Fundamentals1. アルゴリズムとデータ構造 第 3 回 前半部. 目次 :. 基本的なデータ構造 線形リスト スタック キュー ハッシュテーブル 初歩的過ぎる ので 教科書を自分で読むこと. (平均的な効率の解析は難しい MIT本を見よ).. 線形リスト. 直観. データを一列に並べて 覚えたもの. データを 一列に 並べたもの. (データを線形順序に並べたもの). head. 線形リストの例. 各要素:. 9.
E N D
情報システム基盤学 基礎1アルゴリズムとデータ構造 Elements of Information Systems Fundamentals1 アルゴリズムとデータ構造 第3回 前半部
目次: • 基本的なデータ構造 • 線形リスト • スタック • キュー • ハッシュテーブル 初歩的過ぎる ので 教科書を自分で読むこと. (平均的な効率の解析は難しい MIT本を見よ).
線形リスト 直観 データを一列に並べて覚えたもの データを一列に並べたもの (データを線形順序に並べたもの) head 線形リストの例 各要素: 9 4 1 16 16 前の要素へのポインタ 次の要素へのポインタ 1つの要素はprev,key,nextの組 prev next key prev next 次/前の要素がなければNULL key NULL: データ
様々な線形リスト 1. 単一方向の線形リスト head 2. 双方向の線形リスト head 9 1 9 9 9 4 4 4 16 1 1 1 3. ソートされた双方向の線形リスト 16 16 16 4 head 4. ソートされてない双方向の線形リスト head
線形リストに対する命令 探索(search) 与えられた値kをもつ要素を返す 挿入(insert) 与えられた値kをもつ要素を線形リストの先頭へ挿入する 削除(delete) 与えられた値kをもつ要素を削除する
探索 値kが与えられたとき, 値 kをもつ要素返す 1. 値kをもつ要素を見つける 先頭から順々に調べていく(線形探索) 2. 見つけた要素を返す, なかったらNULLを返す 例 下記のリストに対して 9 4 4 1 16 値 4 が与えられたならば, 答えとして を返す head 線形探索
探索の擬似コード ポインタ = 要素の名前と解釈すればプログラミングしやすいかもしれません head: 線形リストの先頭要素 x: 線形リスト上の1要素を表現 9 4 1 16 key[x]: 要素 x がもつ値 計算時間: next[x]: 要素 x の次の要素 O(n) 時間 prev[x]: 要素 x の前の要素 head
挿入 要素 xが与えられたとき, xを線形リストの先頭に加える 例 下記のリストに対して値 25 をもつ要素が与えられたとすると head 9 9 25 4 4 1 1 16 16 挿入 head
挿入の擬似コード x head head: 線形リストの先頭要素 x: 線形リスト上の1要素を表す key[x]: 要素 x がもつ値 next[x]: 要素 x の次の要素 計算時間: prev[x]: 要素 x の前の要素 O(1) 時間
削除 要素 xが与えられたとき, xを削除 例 下記のリストに対して値 4 をもつ要素が与えられたとすると head 9 9 25 4 25 1 1 16 16 削除 head
削除の擬似コード x head head: 線形リストの先頭要素 x: 線形リスト上の1要素を表す key[x]: 要素 x がもつ値 next[x]: 要素 x の次の要素 計算時間: prev[x]: 要素 x の前の要素 O(1) 時間
目次: 今日やること • 基本的なデータ構造 • 線形リスト • スタック • キュー • ハッシュテーブル • 課題
スタック(Stack) もっとも基本的なデータ構造のひとつ 木の探索を表現(深さ優先探索) Last-in first-out(LIFO)
スタックを例えると 出入口が1つだけの満員電車 電車の中へ 出入口 A B C D 電車(だと思ってください)
スタックを例えると 最後に入った人が最初に出る仕組み 出入口が1つだけの満員電車 電車の外へ 出入口 A B C D 電車(だと思ってください)
13 8 8 10 10 10 スタックのイメージ データの流れ 縦長の箱に, データを一列に入れていく 注意:データの出入口は1つだけ 5 12 30 提供されている命令 スタック プッシュ(push): データの追加 ポップ(pop): データの削除 例 8 10 10 10を追加 8を追加 13を追加 削除 削除
プッシュ命令 与えられた要素 xをスタックの先頭に追加 要素が1つだけ増える 125 5 5 値125 をもつ要素をプッシュ 12 12 30 30 スタック スタック
プッシュ命令の擬似コード ※線形リストでスタックが実装されていたと仮定 x 125 top top 125 5 5 12 12 30 30 線形リストの挿入と同じ スタック スタック
ポップ命令 スタックの先頭の要素を削除 ※要素を選んだりはしない 要素が1つだけ減る 5 ポップ 12 12 30 30 スタック スタック
ポップ命令の擬似コード ※線形リストでスタックが実装されていたと仮定 top top 5 ポップ 12 12 30 30 スタック スタック
スタックと木の探索の関連 次の操作をやってみる 深さ優先探索で, 1. 頂点vへ初めて訪れたとき, vをプッシュ 2. 頂点 vを最後に訪れるときポップ 7 1 1 Start End 6 5 4 2 4 3 6 5 3 2 7
木構造 木構造:上から下へ枝分かれした構造 r :頂点(点) :辺 a b c d :根 e f h i g j 親と子 葉と内点 祖先と子孫 m k l 頂点 x を根とする部分木 深さ n 木(根つき木)の例
木構造 木構造:上から下へ枝分かれした構造 r :頂点(点) :辺 a b c d :根 e 親と子 f h i g j 隣接する2頂点のうち, ・根に近い方 → 親 ・根から遠い方 → 子 m k l n 木(根つき木)の例
目次: 今日やること • 基本的なデータ構造 • 線形リスト • スタック • キュー • ハッシュテーブル • 課題
キュー(Queue) もっとも基本的なデータ構造のひとつ 待ち行列を表現 First-in first-out(FIFO) レジ 待っている人の列
キューのイメージ 入口 出口 横長の箱にデータを出し入れ ※データの入口と出口の2つがある データの流れ 提供されている命令 エンキュー(enqueue): データの追加 デキュー(dequeue): データの削除 3 20 20 23 20 23 3 3 20 23 3 23 20をエンキュー 23をエンキュー 3をエンキュー デキュー デキュー
エンキュー(Enqueue) 与えられた要素 xをキューの最後尾に追加 tail head 14 5 20 値34をもつ要素をエンキュー tail head 14 5 20 34
エンキューの擬似コード ※線形リストでスタックが実装されていたと仮定 tail head x 34 14 5 20 x: 挿入する要素 値34をもつ要素をエンキュー tail head 14 5 20 34
デキュー(Dequeue) キューの先頭の要素を削除 tail head 14 5 20 34 デキュー tail head 20 34 14 5
デキューの擬似コード ※線形リストでスタックが実装されていたと仮定 tail head 14 5 20 34 デキュー tail head 20 34 14 5
目次: 今日やること • 基本的なデータ構造 • 線形リスト • スタック • キュー • ハッシュテーブル • 課題
ハッシュテーブル (Hash Table) ハッシュテーブル もっとも基本的なデータ構造のひとつ 0 欲しいデータを素早く検索 1 比較的、省スペースで実現できる (検索スピードとスペースはトレードオフ) 2 3 4 12 2 正の整数の集合 4 6 3 1 0 10 8 5 12 9 7 2 9 4 11 8
ハッシュの概要 1/2 やりたいこと:集合の一部を保存したい 線形リストを利用すれば実現可能 正の整数の集合 挿入: O(1) 時間 削除: O(1) 時間 探索: O(n) 時間 スペース: 保存する整数分だけ 6 3 1 0 10 5 9 7 2 もう少しスペースを使ってもいいから、 効率よく探索を行いたいなぁ・・・ 8 4 11 12 保存する整数の集合は可変なので、 挿入・削除も効率よくやりたいな・・・ (緑部分は可変) ハッシュ
ハッシュの概要 2/2 ハッシュテーブルと呼ぶ テーブル (配列だと思えば良い) 基本方針: テーブルに要素を保存する 0 ハッシュ値と呼ぶ ハッシュ関数と呼ぶ 1 12 正の整数の集合 2 2 関数 h 3 6 3 h(k) k 1 0 10 4 4 5 9 7 2 8 4 11 12 任意に取り出し てきたk について考えます 8 9 気になること ハッシュ関数の決め方 k h(k) ハッシュ値が等しいとき(衝突)はどうする?
ハッシュ関数 様々なハッシュ関数が知られている 良いハッシュ関数 テーブル上に整数を一様にばらまく(一様ハッシュ関数) 計算が簡単 今回は、除算法(division method)を用いる 除算法では以下のハッシュ関数を使用 h(k) = k mod p k: 保存したい整数 p: 自分で決める値(素数がよい) テーブルサイズはp – 1 とする
ハッシュテーブルの例 ハッシュ テーブル 0 190 下記の整数をハッシュテーブルで保存する 1 77 2 {3, 5, 77, 109, 190, 245, 832, 852, 9924, 10346} 3 3 4 ハッシュ関数は下記のように定義 5 5 6 9924 h(k) = k mod 19 7 8 このとき, 各整数のハッシュ値は次の通り 9 10 10346 p =19 としてます h(3) = 3, h(5) = 5, h(77) = 1, h(109) = 14, h(190) = 0, h(245) = 17, h(832) = 15, h(852) = 16, h(9924) = 6, h(10346) = 10 11 12 13 14 109 15 832 ここで, もし, 整数 25 を挿入したいとしたら・・・ 16 852 h(25) = 6となり, すでに 9924 が格納されている 245 17 18 (これを衝突と呼ぶ) ど、どうしよう。。。
衝突回避 その1: チェイン法(Chaning) ハッシュ テーブル 0 190 1 77 2 リストを使って衝突を回避 3 3 各スロットに複数の要素を対応させる 4 5 5 456 25 44 6 9924 7 各スロットについて線形リストを保持する 8 9 10 10346 例 11 h(25) = 6: スロット6で衝突→ スロット6のリストへ追加 12 13 h(456) = 0: スロット0で衝突→ スロット0のリストへ追加 14 109 h(44) = 6: スロット6で衝突→ スロット6のリストへ追加 15 832 16 852 245 17 デメリット: 使用していないスペースがまだあるのに, 他のスペースを使ってしまう 18
衝突回避 その2:線形探査(Linear Probing) ハッシュ テーブル 0 190 1 77 線形探査の流れ 2 1. スロット i で衝突が発生 3 3 2. スロット i + 1 をチェック 4 5 5 3. スロット i + 1 が空きならば, そこへ整数を保存、終了 6 9924 91 25 4. そうでないならば, iをインクリメントして 1. へ戻る 7 25 例 8 9 10 10346 11 h(25) = 6: スロット6で衝突→ スロット7へ 12 スロット7が空きなので、そこへ追加 13 14 109 h(91) = 15: スロット15で衝突→ スロット16へ 15 832 スロット16で衝突 → スロット17へ 16 852 スロット17で衝突 → スロット18へ 245 17 デメリット: クラスタができてしまい、 追加・探索が極端に遅くなるかもしれない スロット18が空きなので、そこへ追加 18 91
Note: 本スライドは山中克久 助教(当時)が 2010年度に作成したものを,今回,大森が 改訂したものです. 2013.4.25.記