PFDS 11.2 catenable double ended queue
- 1. PFDS #12
11.2
Catenable Double-Ended Queue
@yuga
2012-12-01
Copyright © 2012 yuga 1
- 2. 動機
Queueを効率よく連結したい
できればO(1)で
Copyright © 2012 yuga 2
- 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 3
- 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 4
- 5. 解決の方針
DequeをDequeにいれる
(Structural Abstraction)
BootStrapped type SimpleCatenableDeque (初級編)
ImplicitCatenableDeque (上級編)
Primitive type これまでに登場したDeque
(ただしImplicitCatenableDequeの実装には
Dequeの要素数を返すsize関数の実装が必要)
※すべての関数がO(1)時間で実行可能であること。
(実時間/償却時間いずれでもよい)
Copyright © 2012 yuga 5
- 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 6
- 7. 図解: 実装 (cons)
consやsnocは直接PrimitiveのDequeに要素を入れる。
0 1 2
SHALLOW
‘a
D.queue
0 1 2 3 4
DEEP
front middle rear
Copyright © 2012 yuga 7
- 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 8
- 9. 図解: 実装 (++)
1. どちらかが2未満の要素を持つSHALLOW同士の連結
1 2
++ 3
SHALLOW
‘a
D.queue
1 2 3
Copyright © 2012 yuga 9
- 10. 図解: 実装 (++)
2. どちらも2以上の要素をもつSHALLOW同士の連結
1 2
++ 3 4
1 2 3 4
DEEP
front middle rear
Copyright © 2012 yuga 10
- 11. 図解: 実装 (++) ++
3. DEEPと2未満の要素を持つSHALLOWの連結
1 2 3 4 ++ 5
1 2 3 4 5
Copyright © 2012 yuga 11
- 12. 図解: 実装 (++)
5a. DEEPと2以上の要素を持つSHALLOWの連結
1 2 3 4 ++ 5 6
1 2 3 4 5 6
Copyright © 2012 yuga 12
- 13. 図解: 実装 (++)
5a. DEEP同士の連結( middle:どちらかが2未満の要素を持つSHALLOW同士の連結)
1 2 3 4 ++ 5 6 7 8
3 4 ++ 5 6
3 4
1 2 7 8
5 6
Copyright © 2012 yuga 13
- 14. 図解: 実装 (++)
5b. DEEP同士の連結(middle:どちらも2以上の要素をもつSHALLOW同士の連結)
++
3 4 11 12
1 2 7 8 9 10 15 16
5 6 13 14
3 4 9 10
5 6 ++ 11 12
7 8 13 14
3 4 9 10
1 2 5 6 11 12 15 16
7 8 13 14
14
Copyright © 2012 yuga
- 15. 図解: 実装 (++)
5e. DEEP同士の連結(middle:DEEP同士の連結)
3 4 9 10 19 20 25 26
1 2 5
7
6
8
11
13
12
14
15 16
++ 17 18 21
23
22
24
27
29
28
30
31 32
3 4 9 10 17 18 25 26
++
5 6 11 12 19 20 27 28
7 8 13 14 21 22 29 30
15 16 23 24
9 10 17 18
11 12 19 20
13 14
++ 21 22
15 16 23 24
15
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 16
- 17. 図解: 実装 (tail)
1. SHALLOWをtail
1 2 3
1 2 3
Copyright © 2012 yuga 17
- 18. 図解: 実装 (tail)
2. DEEP(frontが3個以上)をtail
2 3 4 5 6 7 8
2 3 4 5 6 7 8
Copyright © 2012 yuga 18
- 19. 図解: 実装 (tail)
3. DEEP(frontが2個、middleが0個)をtail
1 2 3 4
1 2 3 4
1 1 2 3
Copyright © 2012 yuga 19
- 20. 図解: 実装 (tail)
4. DEEP(frontが2個、middleが1個以上)をtail
3 4
1 2 7 8
5 6
3 4
1 2 7 8
5 6
2
1 7 8
3 4 5 6
1 2 3 4 5 6 7 8
Copyright © 2012 yuga 20
- 21. Exercise 11.3: tailが償却実行時間O(1)か?
DEEPに、middleのsuspensionを作成するとき、そのmiddleに1 debitを割り当てる。
次にmiddleを操作するときまでに返却しなければならない。
Debit Invariant:
0 if frontが2個
DEEPのdebit数の上限 =
1 if frontが3個以上
tail時に繰り下がり処理のため
middleを操作することになるから
Copyright © 2012 yuga 21
- 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)
Copyright © 2012 yuga 23