by しんぺい a.k.a. 猫型蓄音機Perlで学ぼう!文系プログラマのための知識ゼロからのデータ構造と計算量
View Slide
あんただれ• しんぺいとか猫型とかいう名前で呼ばれています• rerakuという会社で働いてます• 仕事ではScala, Perl, Ruby
あんただれ• Github:Shinpeim• process-book• 新潟非在住 Niigata.pm 主催です• 趣味でバンド• 11/14高円寺ペンギンハウス
ペンギンハウス
今日やること• データ構造と計算量について、簡単に解説します• 基本的なことしかやりません• ハイレベルプログラマ諸氏は今すぐ別の部屋で有意義な時間を過ごすんだ!!
事前準備
Cの変数とメモリ
何がおきてる?
int のメモリを確保JOUB
1を代入JOUB
bも同様にJOUBJOUC
c も同様にJOUDJOUBJOUC
CPUが足し算してcに代入JOUDJOUBJOUC
ポイント• 変数は箱ではない!!!!!!• メモリです• たくさん用意すれば用意するほどメモリを消費する
メモリとポインタ
実はメモリには番地がありますB10000番
番地を取得B10000番
番地を保存する4byte確保TIPSUCB10000番
番地を代入TIPSUCB10000番
bの中身を10進数で表示TIPSUCB10000番
bの番地の指し示す先を見て10000番TIPSUCB
short* なので2バイト読むTIPSUCB
ポイント• ポインタの中には「メモリ上の位置」を表す数字が入ってる• その数字の番地から、ポインタが示す型のバイト数だけ読めばポインタの指す値を読むことができる• こうやって「値につながる値」を作ることができる
練習問題へんな値が出力されるのはなぜ?
Perlの場合
SVを確保47
AVを確保47 "7
HVを確保47 "7 47 )7 B
SVを確保してSVの場所を代入47 "7 47 )7 47 B47 47 SFG YGEEC0x7f99d080db78
中身を表示47 "7 47 )7 47 B47 47 SFG YGEEC
中身の指し示すやつを取ってきて表示47 "7 47 )7 47 B47 47 SFG YGEEC0x7f99d080db78
ポイント• 値はメモリに確保されてる• リファレンスにはそのメモリの場所を示すものが入っている• ねっ、CもPerlも変わらないでしょ
さまざまなデータ構造
エントリーナンバー1
配列
なにがおきてる?
short5個分を「連続して」確保10000番
変数名でアクセスすると番地が取れる10000番
添え字付きアクセス 10000 + short(2byte) * 2 番地を読みに行くよ10000番
添え字付きアクセス
配列の要素を増やしたい
エントリーナンバー2
単方向連結リスト
単方向連結リストの要素a next element
要素一個つくる要素一個つくる
要素一個つくる)7 @WBMVF@[email protected] 1
要素一個つくる)7 @WBMVF@[email protected][email protected]&MFNFOUSFG 1
ふたつめの要素作る)7 @WBMVF@[email protected][email protected]&MFNFOUSFG )7 @WBMVF@[email protected]&MFNFOUSFG [email protected]&MFNFOUSFG 12
$el_ 1もう出てこないので無視)7 @WBMVF@[email protected])7 @WBMVF@[email protected]&MFNFOUSFG [email protected]&MFNFOUSFG 12
同様にみっつめの要素)7 @WBMVF@[email protected])7 @WBMVF@[email protected]&MFNFOUSFG [email protected]&MFNFOUSFG )7 @WBMVF@[email protected]&MFNFOUSFG 123
Listの実装コンストラクタリストの先頭に値を追加するメソッド
空のリストを作って)7 @[email protected]VOEFGMJTU-JTUSFG
要素をひとつ挿入)7 @[email protected]VOEFGMJTU-JTUSFG )7 @WBMVF@[email protected]
要素をひとつ挿入)7 @[email protected]&MFNFOUSFG MJTU-JTUSFG )7 @WBMVF@[email protected]
2を挿入MJTU-JTUSFG )7 @WBMVF@[email protected])7 @[email protected]&MFNFOUSFG )7 @WBMVF@[email protected]&MFNFOUSFG
3つめの値を取得したいMJTU-JTUSFG )7 @WBMVF@[email protected]&MFNFOUSFG )7 @[email protected]&MFNFOUSFG )7 @WBMVF@[email protected]&MFNFOUSFG )7 @WBMVF@[email protected]
MJTU-JTUSFG )7 @WBMVF@[email protected]&MFNFOUSFG )7 @[email protected]&MFNFOUSFG )7 @WBMVF@[email protected]&MFNFOUSFG )7 @WBMVF@[email protected]3つめの値を取得したい
ポイント• メモリアドレスが飛び飛び• 「空いてるところ」にメモリ確保できる• 先頭からの順々に辿らないといけないので一発でアクセスできない
一発とか順々とかちょっとふわっとしてるもうちょっとちゃんと言いたい
ここでちょっと寄り道計算量の話
オーダー法• データの数がn個のとき、n回計算をしないといけないとき、O(n)という• 2n回計算しないといけない、とか、2n + a回計算しないといけないときもO(n)という• 要するに定数倍とか定数項は考えない
連結リストの計算量• n個めの要素にアクセスしたい• 最初の要素へのアクセス + n - 1回辿る必要がある = O(n)• リストの最初に値を挿入したい• 後ろにいくつ要素があっても、最初の要素へのアクセス + 新しい要素を作ってつなぐだけ = O(1)
配列の計算量• n個めの要素にアクセスしたい• 計算で一発でメモリ番地が出せて、そこを読むだけでよい• O(1)
いろんな計算量をグラフでみると特徴がわかる
O(n)ԣ࣠ɿσʔλͷݸॎ࣠ɿܭࢉͷྔԣ࣠ɿσʔλͷݸॎ࣠ɿܭࢉͷྔ
O(n^2)ԣ࣠ɿσʔλͷݸॎ࣠ɿܭࢉͷྔ
O(1)ԣ࣠ɿσʔλͷݸॎ࣠ɿܭࢉͷྔ
O(log n)
O(log n)ԣ࣠ɿσʔλͷݸॎ࣠ɿܭࢉͷྔ
ポイント• オーダー法は「正確な計算量」を導かない• データの量に応じて、「データが増えたときにどれくらい処理量が増えるか」をざっと知るための指標です
データ構造の話に戻ります
連結リストの特徴• 探索の計算量がO(n)だった• 悪くないけどO(log n)だと嬉しいですよねー
エントリーナンバー3
2分木
2分木のnodeax
)7 @SPPUVOEFGUSFF5SFFSFG tree空の2分木
)7 @SPPUVOEFGUSFF5SFFSFG tree2分木に最初の値:4を追加
2分木に最初の値:4を追加)7 @WBMVF@TNBMMFSVOEFG@MBSHFSVOEFG)7 @SPPU/PEFSFG USFF5SFFSFG tree
2分木に2を追加)7 @WBMVF@TNBMMFS/PEFSFG @MBSHFSVOEFG)7 @SPPU/PEFSFG USFF5SFFSFG )7 @WBMVF@TNBMMFSVOEFG@MBSHFSVOEFGtree
2分木に2を追加)7 @WBMVF@TNBMMFS/PEFSFG @MBSHFSVOEFG)7 @SPPU/PEFSFG USFF5SFFSFG V)7 @WBMVF@TNBMMFSVOEFG@MBSHFSVOEFGtree
2分木に6を追加)7 @WBMVF@TNBMMFS/PEFSFG @MBSHFSVOEFG)7 @SPPU/PEFSFG USFF5SFFSFG V)7 @WBMVF@TNBMMFSVOEFG@MBSHFSVOEFGtree
2分木に6を追加)7 @WBMVF@TNBMMFS/PEFSFG @MBSHFS/PEFSFG )7 @SPPU/PEFSFG USFF5SFFSFG V V)7 @WBMVF@TNBMMFSVOEFG@MBSHFSVOEFG)7 @WBMVF@TNBMMFSVOEFG@MBSHFSVOEFGtree
2分木に3を追加)7 @WBMVF@TNBMMFS/PEFSFG @MBSHFS/PEFSFG )7 @SPPU/PEFSFG USFF5SFFSFG V V)7 @WBMVF@TNBMMFSVOEFG@MBSHFSVOEFG)7 @WBMVF@TNBMMFSVOEFG@MBSHFSVOEFGtree
2分木に3を追加)7 @WBMVF@TNBMMFS/PEFSFG @MBSHFS/PEFSFG )7 @SPPU/PEFSFG USFF5SFFSFG )7 @WBMVF@TNBMMFSVOEFG@MBSHFSVOEFG)7 @WBMVF@TNBMMFSVOEFG@MBSHFSVOEFGV V tree
2分木に3を追加)7 @WBMVF@TNBMMFS/PEFSFG @MBSHFS/PEFSFG )7 @SPPU/PEFSFG USFF5SFFSFG )7 @WBMVF@TNBMMFSVOEFG@MBSHFS/PEFSFG )7 @WBMVF@TNBMMFSVOEFG@MBSHFSVOEFG)7 @WBMVF@TNBMMFSVOEFG@MBSHFSVOEFGV V Vtree
2分木から1を探索)7 @WBMVF@TNBMMFS/PEFSFG @MBSHFS/PEFSFG )7 @SPPU/PEFSFG USFF5SFFSFG )7 @WBMVF@TNBMMFSVOEFG@MBSHFS/PEFSFG )7 @WBMVF@TNBMMFSVOEFG@MBSHFSVOEFG)7 @WBMVF@TNBMMFSVOEFG@MBSHFSVOEFGV V Vtree
2分木の探索• 4つ要素があるけど2回で済んだ• こういう風にちゃんと「ばらけた」木になってるとO(log n)になる
2分木から5を探索)7 @WBMVF@TNBMMFSVOEFG@MBSHFS/PEFSFG )7 @SPPU/PEFSFG USFF5SFFSFG )7 @WBMVF@TNBMMFSVOEFG@MBSHFS/PEFSFG )7 @WBMVF@TNBMMFSVOEFG@MBSHFS/PEFSFG )7 @WBMVF@TNBMMFSVOEFG@MBSHFSVOEFG
2分木の探索• 実質連結リスト• O(n)じゃん
エントリーナンバー4
B木
B木のnodebax
空のB木に7を追加
B木に3を追加
B木に9を追加 満員じゃん
B木に9を追加 全員並べて
B木に9を追加 nodeふたつに分けて
B木に9を追加nodeふたつに分けて
B木に9を追加真ん中の値の行き場がない
B木に9を追加 新しいnode作る
B木に9を追加 枝つなぐ
B木に9を追加 見やすいように整列!
B木に5を追加
B木に6を追加 満員じゃん
B木に6を追加 全員並べて
B木に6を追加 nodeふたつに分けて
B木に6を追加 真ん中は上に空きがあるのでそこに入れる
B木に6を追加
B木に6を追加 枝つなぎ直す
B木に6を追加 見やすいように整列!
B木に10を追加
B木に16を追加満員じゃん
B木に16を追加真ん中は上に
B木に16を追加
B木に16を追加node分割して枝つなぎ直す
B木に16を追加新しいnode作って枝つなぐ
B木に16を追加O(log n)O(m)
エントリーナンバー5
B+木
B+木• DBのインデックスとかに使われてる• B木の改良版• 末端のnodeに全部のデータが入ってる• node同士がlinkされてることが多い
B+木から5を探索 select * from table where id > 5
まとめ
まとめ• データ構造と計算量について簡単に見てみました• この程度の理解でも、ふだんの業務に活かせることは増えます• 今後の学習や業務に活かしていただければ幸いです
最後に• 11/14 高円寺ペンギンハウス• よろしくおねがいします
おしまい