10.4 モジュールを使ったプログラミング例
問 10.6
以下の実行結果を予測せよ.
BF.bf (fromPreOrder "1(2(3()())(4()()))(5()())");
さらに,実際にテストを行い,結果を確認せよ.
解答例 幅優先探索であるから、ルートから同一レベルのルートが順に探索される。 従って、1,2,5,3,4の順に探索されるはずである。 実際、SML#での実行結果は以下の通りである。
# BF.bf (fromPreOrder "1(2(3()())(4()()))(5()())"); val a = ["1", "2", "5", "3", "4"] : string list
問 10.7
解答例 ITQueue、 BFI、 fromIntPreOrxder の定義例を以下に示す。
structure ITQueue :> POLY_QUEUE where type elem = int tree =
struct
exception EmptyQueue
type elem = int tree
type queue = elem list ref * elem list ref
fun newQueue () = (ref [],ref []) : queue
fun enqueue (i,(a,b)) = a := i :: (!a)
fun dequeue (ref [],ref []) = raise EmptyQueue
| dequeue (a as ref L, b as ref []) =
let val (h::t) = rev L
in (a:=nil; b:=t; h)
end
| dequeue (a,b as ref (h::t)) = (b := t; h)
end
structure BFI = struct
structure Q = ITQueue
fun bf t =
let val queue = Q.newQueue()
fun loop () =
(case Q.dequeue queue of
Node(data,l,r) => (Q.enqueue (l,queue);
Q.enqueue (r,queue);
data::loop())
| Empty => loop())
handle Q.EmptyQueue => nil
in (Q.enqueue (t,queue); loop())
end
end
fun fromIntPreOrder s =
if s = "" then Empty
else let val (root,left,right) = decompose s
val SOME data = Int.fromString root
in Node(data, fromIntPreOrder left, fromIntPreOrder right)
end
SML#によるBFI.bfのテスト結果は以下の通りである。
# val intList = BFI.bf (fromIntPreOrder "1(2(3()())(4()()))(5()())"); val intList = [1, 2, 5, 3, 4] : int list
問 10.8
string tree を要素とする待ち行列を, 関数型待ち行列による方法,および, 単純なリストによる実現法 の2通りの方法で定義し,それぞれに対してBFのQストラクチャの定義 を変更し,いずれの場合も BF が正しく動くことを確かめよ.
解答例 それぞれのBFの定義例を以下にしめす。 以下では、単純なリストの場合のストラクチャ名をBFSimpleとしてある。
structure STQueue :> POLY_QUEUE where type elem = string tree = struct
exception EmptyQueue
type elem = string tree
type queue = elem list ref * elem list ref
fun newQueue () = (ref [],ref []) : queue
fun enqueue (i,(a,b)) = a := i :: (!a)
fun dequeue (ref [],ref []) = raise EmptyQueue
| dequeue (a as ref L, b as ref []) =
let val (h::t) = rev L
in (a:=nil; b:=t; h)
end
| dequeue (a,b as ref (h::t)) = (b := t; h)
end
structure BF = struct
structure Q = STQueue
fun bf t =
let val queue = Q.newQueue()
fun loop () =
(case Q.dequeue queue of
Node(data,l,r) => (Q.enqueue (l,queue);
Q.enqueue (r,queue);
data::loop())
| Empty => loop())
handle Q.EmptyQueue => nil
in (Q.enqueue (t,queue); loop())
end
end
structure STQueueSimple :> POLY_QUEUE where type elem = string tree = struct
exception EmptyQueue
type elem = string tree
type queue = elem list ref
fun newQueue() = ref nil : queue
fun enqueue (item,queue) =
queue := item :: (!queue)
fun removeLast nil = raise EmptyQueue
| removeLast [x] = (nil,x)
| removeLast (h::t) =
let val (t’,last) = removeLast t
in (h::t’,last)
end
fun dequeue queue =
let val (rest,last) = removeLast (!queue)
in (queue:=rest; last)
end
end
structure BFSimple = struct
structure Q = STQueueSimple
fun bf t =
let val queue = Q.newQueue()
fun loop () =
(case Q.dequeue queue of
Node(data,l,r) => (Q.enqueue (l,queue);
Q.enqueue (r,queue);
data::loop())
| Empty => loop())
handle Q.EmptyQueue => nil
in (Q.enqueue (t,queue); loop())
end
end
SML#によるテスト実行結果は以下の通りである。
# val a = BF.bf (fromPreOrder "1(2(3()())(4()()))(5()())"); val a = ["1", "2", "5", "3", "4"] : string list # val b = BFSimple.bf (fromPreOrder "1(2(3()())(4()()))(5()())"); val b = ["1", "2", "5", "3", "4"] : string list
問 10.9
BF ストラクチャに,以下の引数を受け取り結果を返す汎用な関数 bffold の定義を追加せよ.
-
1.
木が空のとき返す値
-
2.
空でない木に対して,ルートノードのデータと, ルート以外のノードを幅優先でたどり処理した結果を受け取り,最終結果を返す関数.
BF ストラクチャの bf 関数をごくわずか変更するだけで, 簡単に定義できるはずである.
bffold は,上記の関数 bf とリストの foldr 関数を組み 合わせて得られる関数と同一の動きをするはずである. 以下の2つの関数が同一の動作をすることをテストによって確かめよ.
-
•
BF.bffold f z t
-
•
foldr f z (BF.bf t)
解答例 bffoldを含むBFの定義例を示す。 bfとbffoldはほぼ同一の構造をもち、かつ前者は後者を使って簡単に定義できるため、 以下の例では、bfの定義をbffoldを使って定義してある。
structure BF = struct
structure Q = STQueue
fun bffold f z t =
let val queue = Q.newQueue()
fun loop () =
(case Q.dequeue queue of
Node(data,l,r) => (Q.enqueue (l,queue);
Q.enqueue (r,queue);
f (data, loop()))
| Empty => loop())
handle Q.EmptyQueue => z
in (Q.enqueue (t,queue); loop())
end
fun bf t = bffold (op ::) nil t
end
以下は、SML#によるテスト例である。
# val a = BF.bf (fromPreOrder "1(2(3()())(4()()))(5()())"); val a = ["1", "2", "5", "3", "4"] : string list # val b = BF.bffold (op ::) nil (fromPreOrder "1(2(3()())(4()()))(5()())"); val b = ["1", "2", "5", "3", "4"] : string list # val c = BF.bffold (op ^) "" (fromPreOrder "1(2(3()())(4()()))(5()())"); val c = "12534" : string # val d = foldr (op ^) "" (BF.bf (fromPreOrder "1(2(3()())(4()()))(5()())")); val d = "12534" : string