関数型電卓プログラム fcalc の使用例として、基本的なデータ構造である「二分木」と「ハッシュ表」を作成します。そして、それらを使って「8パズル」を解いてみましょう。
二分木の詳しい説明は拙作のページ「モジュール (2)」または Algorithms with Python「二分木とヒープ」をお読みください。
作成する関数と機能概要を下記に示します。
簡単な使用例を示します。
Calc> load("lib.cal");
Calc> load("tree.cal");
Calc> tree = make_tree(fn(x, y) x == y end, fn(x, y) x < y end);
[(), <Function>, <Function>]
Calc> insert_tree(tree, 100, 1);
Calc> insert_tree(tree, 50, 2);
Calc> insert_tree(tree, 150, 3);
Calc> insert_tree(tree, 10, 4);
Calc> insert_tree(tree, 200, 5);
Calc> search_tree(tree, 100);
1
Calc> search_tree(tree, 200);
5
Calc> search_tree(tree, 300);
Calc> foreach_tree(fn(x, y) print(cons(x, y)) end, tree);
(10 . 4)(50 . 2)(100 . 1)(150 . 3)(200 . 5)0
Calc> delete_tree(tree, 100);
Calc> foreach_tree(fn(x, y) print(cons(x, y)) end, tree);
(10 . 4)(50 . 2)(150 . 3)(200 . 5)0
Calc> delete_tree(tree, 10);
Calc> foreach_tree(fn(x, y) print(cons(x, y)) end, tree);
(50 . 2)(150 . 3)(200 . 5)0
Calc> tree1 = list_to_tree(fn(x, y) x == y end, fn(x, y) x < y end,
list(100, 150, 50, 200, 250, 10), list(1,2,3,4,5,6));
[[100, 1, [50, 3, [10, 6, (), ()], ()], [150, 2, (), [200, 4, (), [250, 5, (), ()]]]],
<Function>, <Function>]
Calc> tree_to_list(tree1);
((10 . 6) (50 . 3) (100 . 1) (150 . 2) (200 . 4) (250 . 5))
Calc> fold_tree_left(fn(k, v, a) cons(k, a) end, nil, tree1);
(250 200 150 100 50 10)
Calc> fold_tree_right(fn(k, v, a) cons(k, a) end, nil, tree1);
(10 50 100 150 200 250)
#
# tree.cal : 二分探索木
#
# Copyright (C) 2012-2021 Makoto Hiroi
#
# 節 : [key, value, left, right]
# アクセス関数
def getKey(node) node[0] end
def getValue(node) node[1] end
def getLeft(node) node[2] end
def getRight(node) node[3] end
def putKey(node, x) node[0] = x end
def putValue(node, value) node[1] = value end
def putLeft(node, tree) node[2] = tree end
def putRight(node, tree) node[3] = tree end
# 節の生成
def makeNode(key, value) [key, value, nil, nil] end
# 二分木の生成
# eq は ==、lt は < を判定する関数
def make_tree(eq, lt) [nil, eq, lt] end
# 木は空か
def isEmptyTree(tree) null(tree[0]) end
# 探索
def search_tree(tree, x)
let rec
iter = fn(node)
if null(node) then
nil
else
if (tree[1])(getKey(node), x) then
getValue(node)
else
if (tree[2])(x, getKey(node)) then
iter(getLeft(node))
else
iter(getRight(node))
end
end
end
end
in
iter(tree[0])
end
end
# 最小値のノードを探索
def searchTreeMin(node)
if null(getLeft(node)) then
node
else
searchTreeMin(getLeft(node))
end
end
# 最大値のノードを探索
def searchTreeMax(node)
if null(getRight(node)) then
node
else
searchTreeMax(getRight(node))
end
end
# 最小値を求める
def search_tree_min(tree)
if null(tree[0]) then
nil
else
let
node = searchTreeMin(tree[0])
in
cons(getKey(node), getValue(node))
end
end
end
# 最大値を求める
def search_tree_max(tree)
if null(tree[0]) then
nil
else
let
node = searchTreeMax(tree[0])
in
cons(getKey(node), getValue(node))
end
end
end
# 挿入
def insert_tree(tree, key, value)
let rec
iter = fn(node)
if null(node) then
makeNode(key, value)
else
if (tree[1])(key, getKey(node)) then
putValue(node, value)
else
if (tree[2])(key, getKey(node)) then
putLeft(node, iter(getLeft(node)))
else
putRight(node, iter(getRight(node)))
end
end,
node
end
end
in
tree[0] = iter(tree[0]),
nil
end
end
# 最小値のノードを削除
def deleteTreeMin(node)
if null(getLeft(node)) then
getRight(node)
else
putLeft(node, deleteTreeMin(getLeft(node))),
node
end
end
# 最大値のノードを削除
def deleteTreeMax(node)
if null(getRight(node)) then
getLeft(node)
else
putRight(node, deleteTreeMax(getRight(node))),
node
end
end
# 最小値を削除
def delete_tree_min(tree)
if null(tree[0]) then
nil
else
tree[0] = deleteTreeMin(tree[0]),
tree
end
end
# 最大値を削除
def delete_tree_max(tree)
if null(tree[0]) then
nil
else
tree[0] = deleteTreeMax(tree[0]),
tree
end
end
# 削除
def delete_tree(tree, key)
let rec
iter = fn(node)
if null(node) then
nil
else
if (tree[1])(key, getKey(node)) then
if null(getLeft(node)) then
getRight(node)
else
if null(getRight(node)) then
getLeft(node)
else
let
minNode = searchTreeMin(getRight(node))
in
putKey(node, getKey(minNode)),
putValue(node, getValue(minNode)),
putRight(node, deleteTreeMin(getRight(node))),
node
end
end
end
else
if (tree[2])(key, getKey(node)) then
putLeft(node, iter(getLeft(node)))
else
putRight(node, iter(getRight(node)))
end,
node
end
end
end
in
tree[0] = iter(tree[0]),
nil
end
end
# 畳み込み
def fold_tree_right(f, a, tree)
let rec
iter = fn(node, a)
if null(node) then
a
else
iter(getLeft(node),
f(getKey(node), getValue(node), iter(getRight(node), a)))
end
end
in
iter(tree[0], a)
end
end
def fold_tree_left(f, a, tree)
let rec
iter = fn(node, a)
if null(node) then
a
else
iter(getRight(node),
f(getKey(node), getValue(node), iter(getLeft(node), a)))
end
end
in
iter(tree[0], a)
end
end
# 巡回
def foreach_tree(f, tree)
let rec
iter = fn(node)
if not null(node) then
iter(getLeft(node)),
f(getKey(node), getValue(node)),
iter(getRight(node))
end
end
in
iter(tree[0])
end
end
# list -> tree
def list_to_tree(eq, lt, ks, vs)
foldl2(fn(k, v, a) insert_tree(a, k, v), a end, make_tree(eq, lt), ks, vs)
end
# tree -> list
def tree_to_list(tree)
fold_tree_right(fn(k, v, a) cons(cons(k, v), a) end, nil, tree)
end
「15 パズル」でお馴染みのスライドパズルです。それでは問題です。
┌─┬─┬─┐ ┌─┬─┬─┐ ┌─┬─┬─┐
│8│6│7│ │6│4│7│ │1│2│3│
├─┼─┼─┤ ├─┼─┼─┤ ├─┼─┼─┤
│2│5│4│ │8│5│ │ │4│5│6│
├─┼─┼─┤ ├─┼─┼─┤ ├─┼─┼─┤
│3│ │1│ │3│2│1│ │7│8│ │
└─┴─┴─┘ └─┴─┴─┘ └─┴─┴─┘
スタートA スタートB ゴール
図 : 8 パズル
スタートからゴールまでの最短手順を求めてください。
#
# eight.cal : 8パズル
#
# Copyright (C) 2012-2021 Makoto Hiroi
#
# 隣接行列
# 0 1 2
# 3 4 5
# 6 7 8
adjacent = [[1, 3], [0, 2, 4], [1, 5],
[0, 4, 6], [1, 3, 5, 7], [2, 4, 8],
[3, 7], [4, 6, 8], [5, 7]];
# state : (board prevState spacePosition)
# state のアクセス関数
def getBoard(state) first(state) end
def getPrev(state) second(state) end
def getSpace(state) third(state) end
# 新しい盤面を作る
def makeBoard(b, s, p)
let
n = copy(b)
in
n[s] = n[p],
n[p] = 0,
n
end
end
# 手順の表示
def printAnswer(state)
if getPrev(state) then printAnswer(getPrev(state)) end,
print(getBoard(state)),
print("\n")
end
# 盤面を数値に変換
def boardtoNum(board)
foldl(fn(x, a) a * 10 + x end, 0, board)
end
# 8パズルの解法 (単純な幅優先探索)
def solve8(start, goal)
callcc(fn(exit)
let
q = makeQueue(),
a = make_tree(fn(x, y) x == y end, fn(x, y) x < y end),
g = boardtoNum(goal)
in
insert_tree(a, boardtoNum(start), 1),
enqueue(q, list(start, nil, position(fn(x) x == 0 end, start))),
while not isEmptyQueue(q) do
let
s0 = dequeue(q)
in
foreach(fn(x)
let rec
s1, n = list(makeBoard(getBoard(s0), getSpace(s0), x), s0, x),
boardtoNum(getBoard(s1))
in
if n == g then
printAnswer(s1),
exit(nil)
else
if not search_tree(a, n) then
insert_tree(a, n, 1),
enqueue(q, s1)
end
end
end
end,
adjacent[getSpace(s0)]
)
end
end
end
end)
end
def test1()
solve8([8,6,7,2,5,4,3,0,1],[1,2,3,4,5,6,7,8,0])
end
def test2()
solve8([6,4,7,8,5,0,3,2,1],[1,2,3,4,5,6,7,8,0])
end
実行結果を示します。
Calc> test1();
[8, 6, 7, 2, 5, 4, 3, 0, 1]
[8, 6, 7, 2, 0, 4, 3, 5, 1]
[8, 0, 7, 2, 6, 4, 3, 5, 1]
・・・省略・・・
[1, 2, 3, 4, 5, 6, 0, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 0, 8]
[1, 2, 3, 4, 5, 6, 7, 8, 0]
Calc> test2();
[6, 4, 7, 8, 5, 0, 3, 2, 1]
[6, 4, 0, 8, 5, 7, 3, 2, 1]
[6, 0, 4, 8, 5, 7, 3, 2, 1]
・・・省略・・・
[1, 2, 3, 4, 0, 6, 7, 5, 8]
[1, 2, 3, 4, 5, 6, 7, 0, 8]
[1, 2, 3, 4, 5, 6, 7, 8, 0]
どちらの場合も最短手数は 31 手、これが 8 パズルの最長手数の局面になります。実行時間は、A が 49.6 秒、B が 50.2 秒でした。実行環境は Windows 10, Intel Core i5-6200U 2.30GHz, SML/NJ ver 110.98 です。
二分木は左右の部分木のバランスが崩れると性能が劣化します。二分木の場合、最下層にあるデータを探す場合が最悪で、木の高さ分だけ比較が行われます。したがって、木の高さを低く抑えた方が探索効率も良くなります。このため、木のバランスを一定の範囲に収める「平衡木」が考案されています。有名なところでは AVL 木、赤黒木 (2 色木)、2-3 木、B 木、B* 木などがあります。この中で 2-3 木、B 木、B* 木は多分木、AVL 木、赤黒木は二分木を使用します。今回は簡単に実装できる AA 木を作ってみましょう。AA 木の詳しい説明は拙作のページ Algorithms with Python 「AA 木」をお読みください。
作成する関数は二分木と同じですが、終端を表す節を巡回的な構造でプログラムしているため、節を表示すると無限ループになります。ご注意くださいませ。
簡単な実行例を示します。
Calc> load("lib.cal");
Calc> load("aatree.cal");
Calc> begin tree = make_tree(fn(x, y) x == y end, fn(x, y) x < y end), nil end;
Calc> insert_tree(tree, 100, 1);
Calc> insert_tree(tree, 50, 2);
Calc> insert_tree(tree, 150, 3);
Calc> insert_tree(tree, 10, 4);
Calc> insert_tree(tree, 200, 5);
Calc> insert_tree(tree, 250, 6);
Calc> search_tree(tree, 10);
4
Calc> search_tree(tree, 100);
1
Calc> search_tree(tree, 250);
6
Calc> delete_tree(tree, 100);
Calc> delete_tree(tree, 10);
Calc> delete_tree(tree, 250);
Calc> search_tree(tree, 10);
Calc> search_tree(tree, 100);
Calc> search_tree(tree, 250);
Calc> begin tree1 = list_to_tree(fn(x, y) x == y end, fn(x, y) x < y end,
list(10, 20,30,40,50,60,70), list(1,2,3,4,5,6,7)), nil end;
Calc> foreach_tree(fn(k, v) print(cons(k, v)) end, tree1);
(10 . 1)(20 . 2)(30 . 3)(40 . 4)(50 . 5)(60 . 6)(70 . 7)0
Calc> print_tree(tree1);
10
20
30
40
50
60
70
#
# aatree.cal : 平衡二分木 (AA tree)
#
# Copyright (C) 2012-2021 Makoto Hiroi
#
# 節 : [key, value, left, right, height]
# 終端の生成
begin
Null = [nil, nil, nil, nil, 0],
Null[2] = Null,
Null[3] = Null,
nil
end;
# 終端の判定
def endp(node) node[4] == 0 end
# アクセス関数
def getKey(node) node[0] end
def getValue(node) node[1] end
def getLeft(node) node[2] end
def getRight(node) node[3] end
def getHeight(node) node[4] end
def putKey(node, x) node[0] = x end
def putValue(node, value) node[1] = value end
def putLeft(node, tree) node[2] = tree end
def putRight(node, tree) node[3] = tree end
def putHeight(node, n) node[4] = n end
def incHeight(node) node[4] = node[4] + 1 end
def decHeight(node) node[4] = node[4] - 1 end
# 節の生成
def makeNode(key, value)
[key, value, Null, Null, 1]
end
# AA 木の生成
# eq は ==、lt は < を判定する関数
def make_tree(eq, lt) [Null, eq, lt] end
# 空の木か
def isEmptyTree(tree) endp(tree[0]) end
# 右回転
def rotate_right(node)
let
left_node = getLeft(node)
in
putLeft(node, getRight(left_node)),
putRight(left_node, node),
left_node
end
end
# 左回転
def rotate_left(node)
let
right_node = getRight(node)
in
putRight(node, getLeft(right_node)),
putLeft(right_node, node),
right_node
end
end
# 左の子が赤の場合
def skew(node)
if getHeight(getLeft(node)) == getHeight(node) then
node = rotate_right(node)
end,
node
end
# 右の孫節が赤の場合
def split(node)
if getHeight(node) == getHeight(getRight(getRight(node))) then
node = rotate_left(node),
incHeight(node)
end,
node
end
# 探索
def search_tree(tree, x)
let rec
iter = fn(node)
if endp(node) then
nil
else
if (tree[1])(getKey(node), x) then
getValue(node)
else
if (tree[2])(x, getKey(node)) then
iter(getLeft(node))
else
iter(getRight(node))
end
end
end
end
in
iter(tree[0])
end
end
# 最小値のノードを探索
def searchTreeMin(node)
if endp(getLeft(node)) then
node
else
searchTreeMin(getLeft(node))
end
end
# 最大値のノードを探索
def searchTreeMax(node)
if endp(getRight(node)) then
node
else
searchTreeMax(getRight(node))
end
end
# 最小値を求める
def search_tree_min(tree)
if endp(tree[0]) then
nil
else
let
node = searchTreeMin(tree[0])
in
cons(getKey(node), getValue(node))
end
end
end
# 最大値を求める
def search_tree_max(tree)
if endp(tree[0]) then
nil
else
let
node = searchTreeMax(tree[0])
in
cons(getKey(node), getValue(node))
end
end
end
# 挿入
def insert_tree(tree, key, value)
let rec
iter = fn(node)
if endp(node) then
makeNode(key, value)
else
if (tree[1])(getKey(node), key) then
putValue(node, value),
node
else
if (tree[2])(key, getKey(node)) then
putLeft(node, iter(getLeft(node)))
else
putRight(node, iter(getRight(node)))
end,
split(skew(node))
end
end
end
in
tree[0] = iter(tree[0]),
nil
end
end
# バランスのチェック
def check_balance(node)
if getHeight(getLeft(node)) < getHeight(node) - 1 or
getHeight(getRight(node)) < getHeight(node) - 1 then
decHeight(node),
if getHeight(getRight(node)) > getHeight(node) then
putHeight(getRight(node), getHeight(node))
end,
node = skew(node),
putRight(node, skew(getRight(node))),
putRight(getRight(node), skew(getRight(getRight(node)))),
node = split(node),
putRight(node, split(getRight(node)))
end,
node
end
# 最小値のノードを削除
def deleteTreeMin(node)
if endp(getLeft(node)) then
getRight(node)
else
putLeft(node, deleteTreeMin(getLeft(node))),
check_balance(node)
end
end
# 最大値のノードを削除
def deleteTreeMax(node)
if endp(getRight(node)) then
getLeft(node)
else
putRight(node, deleteTreeMax(getRight(node))),
check_balance(node)
end
end
# 最小値を削除
def delete_tree_min(tree)
if endp(tree[0]) then
nil
else
tree[0] = deleteTreeMin(tree[0]),
nil
end
end
# 最大値を削除
def delete_tree_max(tree)
if endp(tree[0]) then
nil
else
tree[0] = deleteTreeMax(tree[0]),
nil
end
end
# 削除
def delete_tree(tree, key)
let rec
iter = fn(node)
if endp(node) then
node
else
if (tree[1])(key, getKey(node)) then
if endp(getLeft(node)) then
getRight(node)
else
if endp(getRight(node)) then
getLeft(node)
else
let
minNode = searchTreeMin(getRight(node))
in
putKey(node, getKey(minNode)),
putValue(node, getValue(minNode)),
putRight(node, deleteTreeMin(getRight(node))),
check_balance(node)
end
end
end
else
if (tree[2])(key, getKey(node)) then
putLeft(node, iter(getLeft(node)))
else
putRight(node, iter(getRight(node)))
end,
check_balance(node)
end
end
end
in
tree[0] = iter(tree[0]),
nil
end
end
# 畳み込み
def fold_tree_right(f, a, tree)
let rec
iter = fn(node, a)
if endp(node) then
a
else
iter(getLeft(node),
f(getKey(node), getValue(node), iter(getRight(node), a)))
end
end
in
iter(tree[0], a)
end
end
def fold_tree_left(f, a, tree)
let rec
iter = fn(node, a)
if endp(node) then
a
else
iter(getRight(node),
f(getKey(node), getValue(node), iter(getLeft(node), a)))
end
end
in
iter(tree[0], a)
end
end
# 巡回
def foreach_tree(f, tree)
let rec
iter = fn(node)
if not endp(node) then
iter(getLeft(node)),
f(getKey(node), getValue(node)),
iter(getRight(node))
end
end
in
iter(tree[0])
end
end
# list -> tree
def list_to_tree(eq, lt, ks, vs)
foldl2(fn(k, v, a) insert_tree(a, k, v), a end, make_tree(eq, lt), ks, vs)
end
# tree -> list
def tree_to_list(tree)
fold_tree_right(fn(k, v, a) cons(cons(k, v), a) end, nil, tree)
end
# debug 用表示ルーチン
def print_tree(tree)
let rec
iter = fn(node, x)
if not endp(node) then
iter(getLeft(node), x),
let i = x - getHeight(node) in
while i > 0 do
print(" "), i = i - 1
end,
print(getKey(node)),
print("\n")
end,
iter(getRight(node), x)
end
end
in
iter(tree[0], getHeight(tree[0])),
print("\n")
end
end
AA 木を使うと、8パズルの実行時間は二分木よりも速くなります。
| 二分木 | AA 木
--------+--------+-------
test1() | 49.6 s | 38.7 s
test2() | 50.2 s | 40.6 s
実行環境 : Windows 10, Intel Core i5-6200U 2.30GHz, SML/NJ ver 110.98
ハッシュ表の詳しい説明は、拙作のページ「ハッシュ法」または Algorithms with Python 「ハッシュ法」をお読みください。
作成する関数と機能概要を下記に示します。
簡単な使用例を示します。
Calc> h = make_hash(16, equal, fn(xs) foldl(fn(x, a) a * 10 + x end, 0, xs) end); [[(), (), (), (), (), (), (), (), (), (), (), (), (), (), (), ()], <Function>, <Function>] Calc> insert_hash(h, [1,2,3], 1); (([1, 2, 3] . 1)) Calc> insert_hash(h, [4,5,6], 2); (([4, 5, 6] . 2)) Calc> insert_hash(h, [7,8,9], 3); (([7, 8, 9] . 3)) Calc> insert_hash(h, [10,11,12], 4); (([10, 11, 12] . 4)) Calc> insert_hash(h, [13,14,15], 5); (([13, 14, 15] . 5)) Calc> h; [[(), (), (([10, 11, 12] . 4)), (), (), (([7, 8, 9] . 3)), (), (), (([4, 5, 6] . 2)), (), (), (([1, 2, 3] . 1)), (), (), (), (([13, 14, 15] . 5))], <Function>,<Function>] Calc> search_hash(h, [1,2,3]); 1 Calc> search_hash(h, [13,14,15]); 5 Calc> search_hash(h, [3,2,1]); Calc> delete_hash(h, [1,2,3]); Calc> search_hash(h, [1,2,3]); Calc> delete_hash(h, [4,5,6]); Calc> search_hash(h, [4,5,6]); Calc> h; [[(), (), (([10, 11, 12] . 4)), (), (), (([7, 8, 9] . 3)), (), (), (), (), (), (), (), (), (), (([13, 14, 15] . 5))], <Function>, <Function>] Calc> h1 = list_to_hash(16, fn(x, y) x == y end, fn(x) x end, list(10,20,30,40,50,60), list(1,2,3,4,5,6)); [[(), (), ((50 . 5)), (), ((20 . 2)), (), (), (), ((40 . 4)), (), ((10 . 1)), (), ((60 . 6)), (), ((30 . 3)), ()], <Function>, <Function>] Calc> hash_to_list(h1); ((30 . 3) (60 . 6) (10 . 1) (40 . 4) (20 . 2) (50 . 5)) Calc> foreach_hash(fn(k, v) print(cons(k, v)) end, h1); (50 . 5)(20 . 2)(40 . 4)(10 . 1)(60 . 6)(30 . 3) Calc> fold_hash(fn(k, v, a) cons(cons(k, v), a) end, nil, h1); ((30 . 3) (60 . 6) (10 . 1) (40 . 4) (20 . 2) (50 . 5))
#
# hash.cal : ハッシュ表
#
# Copyright (C) 2012-2021 Makoto Hiroi
#
# ハッシュ表の生成
def make_hash(size, eq, hv)
[makeVector(size, nil), eq, hv]
end
# ハッシュ表の位置を求める
def getIndex(ht, key)
(ht[2])(key) % len(ht[0])
end
# 探索
def search_hash(ht, key)
let
v = find(fn(x) (ht[1])(car(x), key) end, ht[0][getIndex(ht, key)])
in
if null(v) then nil else cdr(v) end
end
end
# 挿入
def insert_hash(ht, key, value)
let rec
idx, v = getIndex(ht, key),
find(fn(x) (ht[1])(car(x), key) end, ht[0][idx])
in
if null(v) then
ht[0][idx] = cons(cons(key, value), ht[0][idx])
else
setCdr(v, value)
end
end
end
# 削除
def delete_hash(ht, key)
let
idx = getIndex(ht, key)
in
ht[0][idx] = remove(fn(x) (ht[1])(car(x), key) end, ht[0][idx])
end
end
# 畳み込み
def fold_hash(f, a, ht)
foldl(fn(xs, b) foldl(fn(x, c) f(car(x), cdr(x), c) end, b, xs) end, a, ht[0])
end
# 巡回
def foreach_hash(f, ht)
foreach(fn(xs) foreach(fn(x) f(car(x), cdr(x)) end, xs) end, ht[0])
end
# list -> hash
def list_to_hash(size, eq, hv, ks, vs)
foldl2(fn(k, v, a) insert_hash(a, k, v), a end, make_hash(size, eq, hv), ks, vs)
end
# hash -> list
def hash_to_list(ht)
fold_hash(fn(k, v, a) cons(cons(k, v), a) end, nil, ht)
end
ハッシュ表を使った8パズルの解法プログラムを示します。
リスト : ハッシュ表を使った8パズルの解法
def solve8(start, goal)
callcc(fn(exit)
let
q = makeQueue(),
# 262144, 262147
a = make_hash(262147, fn(x, y) x == y end, fn(x) x end),
g = boardtoNum(goal)
in
insert_hash(a, boardtoNum(start), 1),
enqueue(q, list(start, nil, position(fn(x) x == 0 end, start))),
while not isEmptyQueue(q) do
let
s0 = dequeue(q)
in
foreach(fn(x)
let rec
s1, n = list(makeBoard(getBoard(s0), getSpace(s0), x), s0, x),
boardtoNum(getBoard(s1))
in
if n == g then
printAnswer(s1),
exit(nil)
else
if not search_hash(a, n) then
insert_hash(a, n, 1),
enqueue(q, s1)
end
end
end
end,
adjacent[getSpace(s0)]
)
end
end
end
end)
end
実行結果は次のようになりました。
| 二分木 | AA 木 | Hash
--------+--------+--------+-------
test1() | 49.6 s | 38.7 s | 15.2 s
test2() | 50.2 s | 40.6 s | 15.6 s
実行環境 : Windows 10, Intel Core i5-6200U 2.30GHz, SML/NJ ver 110.98