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