pfds 11.2 catenable double ended queue
DESCRIPTION
SimpleCatenableDeque までです。TRANSCRIPT
Copyright © 2012 yuga 1
11.2
Catenable Double-Ended Queue
PFDS #12
@yuga
2012-12-01
Copyright © 2012 yuga 2
動機
Queueを効率よく連結したい
できればO(1)で
Copyright © 2012 yuga 3
Catenable Deque
連結可能なDequeのシグネチャ
CATENABLEDEQUE :
module type CATENABLEDEQUE = sig type ‘a cat val empty : ‘a cat val isEmpty : ‘a cat -> bool val snoc : ‘a cat * ‘a -> ‘a cat val head : ‘a cat -> ‘a val tail : ‘a cat -> ‘a cat val cons : ‘a * ‘a cat -> ‘a cat val last : ‘a cat -> ‘a val init : ‘a cat -> ‘a cat val (++) : ‘a cat -> ‘a cat -> ‘a cat end
Copyright © 2012 yuga 4
Catenable Deque
連結可能なDequeのシグネチャ
CATENABLEDEQUE :
module type CATENABLEDEQUE = sig type ‘a cat include module DEQUE with type ‘a queue := ‘a cat val (++) : ‘a cat -> ‘a cat -> ‘a cat end
Copyright © 2012 yuga 5
解決の方針
DequeをDequeにいれる (Structural Abstraction)
BootStrapped type SimpleCatenableDeque (初級編)
ImplicitCatenableDeque (上級編)
Primitive type これまでに登場したDeque (ただしImplicitCatenableDequeの実装には
Dequeの要素数を返すsize関数の実装が必要)
※すべての関数がO(1)時間で実行可能であること。
(実時間/償却時間いずれでもよい)
Copyright © 2012 yuga 6
SimpleCatenableDequeの実装
データ構造
SHALLOW … 単体のDeque
DEEP … 連結したDeque
front – middle – rearの3パーツ構成
frontとrearは必ず2個以上の要素を持つ
module SimpleCatenableDeque (D : DEQUE) : CATENABLEDEQUE = struct type ‘a cat = SHALLOW of ‘a D.queue | DEEP of ‘a D.queue (* front *) * ‘a D.queue cat susp (* middle *) * ‘a D.queue (* rear *) …
Copyright © 2012 yuga 7
図解: 実装 (cons)
consやsnocは直接PrimitiveのDequeに要素を入れる。
1 2 0
1 2 3 4
DEEP
front middle rear
D.queue
SHALLOW
‘a
0
Copyright © 2012 yuga 8
実装 (++)
5パターンある。DEEPのmiddleについては再帰的に行う。
1. どちらかが2未満の要素を持つSHALLOW同士の連結
2. どちらも2以上の要素をもつSHALLOW同士の連結
3. DEEPと2未満の要素を持つSHALLOWの連結
4. DEEPと2以上の要素を持つSHALLOWの連結
5. DEEP同士の連結
a. middle:どちらかが2未満の要素を持つSHALLOW同士の連結
b. middle:どちらも2以上の要素をもつSHALLOW同士の連結
c. middle:DEEPと2未満の要素を持つSHALLOWの連結
d. middle:DEEPと2以上の要素を持つSHALLOWの連結
e. middle:DEEP同士の連結
i. middle:…
…
T(m+n) = T((m – (4 + c))/2) + T((n – (4 + d))/2) + O(1)
= O(min (log(m), log(n)))
Copyright © 2012 yuga 9
図解: 実装 (++)
1. どちらかが2未満の要素を持つSHALLOW同士の連結
1 2 3
1 2 3 ++
D.queue
SHALLOW
‘a
Copyright © 2012 yuga 10
図解: 実装 (++)
2. どちらも2以上の要素をもつSHALLOW同士の連結
1 2 3 4
1 2 3 4
++
DEEP
front middle rear
Copyright © 2012 yuga 11
図解: 実装 (++)
3. DEEPと2未満の要素を持つSHALLOWの連結
1 2 3 4
1 2 3 4 ++
++
5
5
Copyright © 2012 yuga 12
図解: 実装 (++)
5a. DEEPと2以上の要素を持つSHALLOWの連結
1 2 5 6
1 2 3 4 ++
3 4
5 6
Copyright © 2012 yuga 13
図解: 実装 (++)
5a. DEEP同士の連結( middle:どちらかが2未満の要素を持つSHALLOW同士の連結)
1 2 7 8
1 2 3 4 5 6 7 8 ++
3 4
5 6
3 4 5 6 ++
Copyright © 2012 yuga
14
図解: 実装 (++)
5b. DEEP同士の連結(middle:どちらも2以上の要素をもつSHALLOW同士の連結)
1 2 15 16
1 2 7 8 3 4
5 6
9 10 15 16
11 12
13 14
3 4
5 6
7 8
9 10
11 12
13 14
3 4
5 6
7 8
9 10
11 12
13 14
++
++
Copyright © 2012 yuga
15
図解: 実装 (++)
5e. DEEP同士の連結(middle:DEEP同士の連結)
1 2 15 16
3 4
5 6
7 8
9 10
11 12
13 14
17 18 31 32
19 20
21 22
23 24
25 26
27 28
29 30
++
3 4
5 6
7 8
9 10
11 12
13 14
15 16
17 18
19 20
21 22
25 26
27 28
29 30
23 24
++
++
9 10
11 12
13 14
15 16
17 18
19 20
21 22
23 24
Copyright © 2012 yuga 16
実装 (tail)
SHALLOWはそのまま。DEEPは先頭を除去後、frontの要素数が2以上になるならそのまま、そうでないならSHALLOWにする。
1. SHALLOWをtail
2. DEEP(frontが3個以上)をtail
3. DEEP(frontが2個、middleが0個)をtail
4. DEEP(frontが2個、middleが1個以上)をtail
Copyright © 2012 yuga 17
図解: 実装 (tail)
1. SHALLOWをtail
1 2 3
1 2 3
Copyright © 2012 yuga 18
図解: 実装 (tail)
2. DEEP(frontが3個以上)をtail
7 8 5 6 3 4 2
7 8 5 6 3 4 2
Copyright © 2012 yuga 19
図解: 実装 (tail)
3. DEEP(frontが2個、middleが0個)をtail
1 2 3 4
1 2 3 1
2 3 4 1
Copyright © 2012 yuga 20
図解: 実装 (tail)
4. DEEP(frontが2個、middleが1個以上)をtail
1 2 7 8
3 4
5 6
1 7 8
3 4
5 6
2
1 7 8
5 6 3 4
2
1 7 8 5 6 3 4 2
Copyright © 2012 yuga 21
Exercise 11.3: tailが償却実行時間O(1)か?
DEEPに、middleのsuspensionを作成するとき、そのmiddleに1 debitを割り当てる。
次にmiddleを操作するときまでに返却しなければならない。
Debit Invariant:
DEEPのdebit数の上限 =
0 if frontが2個 1 if frontが3個以上
tail時に繰り下がり処理のため
middleを操作することになるから
Copyright © 2012 yuga 22
Exercise 11.3: tailが償却実行時間O(1)か?
振り返り(9.2.3 Lazy Representation)
3個以上
2個
繰り下がりを再帰的に行うことでdebitは発生するが、返却が必要なdebitはO(1)
Copyright © 2012 yuga 23
Exercise 11.3: tailが償却実行時間O(1)か?
1. SHALLOWをtail
SHALLOWには既存debitが存在しない。
SHALLOWのtail操作では新規debitは発生しない。
2. DEEP(frontが3個以上)をtail
tail前はfrontが3個以上なので、middleにdebitが1割り当てられている。
middleを操作しないので新規debitは発生しない。
tail操作後、frontが2個になる場合:
– debitの許容数は-1。
– したがって合計1debitを返却する。
3. DEEP(frontが2個、middleが0個)をtail
tail前はfrontが2個なので、middleに割り当てられたdebitは0。
middleを破棄するので新規debitは発生しない。
tail後、SHALLOWになりdebit許容数が-1。
4. DEEP(frontが2個、middleが1個以上)をtail
tail前はfrontが2なので、middleに割り当てられたdebitは0。
middleの操作でsuspensionを作成しているので、middleに新規debitが1発生する。
tail後はfrontは3個以上なので、debit許容数は+1
したがってO(1)