我正在研究Prolog,我发现很难实现一个带有列表并从中构建平衡树的谓词。
我已经实现了构建 AVL树的这些谓词(我从Bratko书中获取它并且工作正常):
%%% A program for constructing and searching an avl tree.
%%% Based on Bratko pp 244ff.
%%% Build the tree.
%% The root of the tree is Key.
addavl( nil/0, Key, avl(nil/0, Key, nil/0)/1 ).
addavl( avl(Left, Y, Right)/Hy, Key, NewTree):-
eq(Y, Key),
!,
NewTree = avl(Left, Y, Right)/Hy.
addavl( avl(Left, Y, Right)/Hy, Key, NewTree):-
gt(Y, Key),
addavl(Left, Key, avl(Left1, Z, Left2)/_ ),
combine(Left1, Z, Left2, Y, Right, NewTree).
addavl( avl(Left, Y, Right)/Hy, Key, NewTree):-
gt(Key, Y),
addavl(Right, Key, avl(Right1, Z, Right2)/_ ),
combine(Left, Y, Right1, Z, Right2, NewTree).
combine(T1/H1, A, avl(T21, B, T22)/H2 , C, T3/H3,
avl(avl(T1/H1, A, T21)/Ha, B, avl(T22, C, T3/H3)/Hc)/Hb ):-
H2 > H1,
H2 > H3,
Ha is H1 + 1,
Hc is H3 + 1,
Hb is Ha + 1.
combine(T1/H1, A, T2/H2, C, T3/H3,
avl(T1/H1, A, avl(T2/H2, C, T3/H3)/Hc)/Ha ):-
H1 >= H2,
H1 >= H3,
max1(H2, H3, Hc),
max1(H1, Hc, Ha).
combine(T1/H1, A, T2/H2, C, T3/H3,
avl(avl(T1/H1, A, T2/H2)/Ha, C, T3/H3)/Hc ):-
H3 >= H2,
H3 >= H1,
max1(H1, H2, Ha),
max1(Ha, H3, Hc).
max1(U, V, Max):-
( U > V,
!,
Max is U + 1
; Max is V + 1
).
eq(X, Y):-
X == Y,
!,
write(X),
write(' Item already in tree\n').
所以我有 addavl(Tree, Element, NewTree/Height)
谓词,它将新元素添加到生成新AVL树的Tree
。
现在我想创建一个新的谓词,使用这个 addavl/3
谓词从元素列表中创建一个新的AVL树。
例如,如果我有列表:[1,2,3]
,则此新谓词将创建一个包含元素 1,2,3 的新AVL树。
我正在努力做到这一点,但我发现有些困难。
我已经实现了类似的东西(但它不起作用):
%% BASE CASE: The list is empty, so there is no element to insert
%% into the AVL Tree:
buildTreeList(Tree, [], NewTree, Height) :- !.
%% If I am inserting the first element in the AVL Tree
%% the hight H of the Tree after the insertion is 1:
buildTreeList(Tree, [Head|Tail], NewTree, 1) :-
addavl(nil/0, Head, avl(nil/0, Head, nil/0)/H),
Tree = nil/0,
NewTree = avl(nil/0, Head, nil/0)/1,
buildTreeList(NewTree, Tail, NT, Height).
buildTreeList(Tree, [Head|Tail], NewTree, H) :-
addavl(Tree, Head, avl(Tree, Head, NewTree)/H),
buildTreeList(NewTree, Tail, NT, Height).
我的想法是: addavl/3
谓词为新的AVL树添加了一个元素,并为我提供了这棵新树的高度(因为我有这对夫妇 NewTree
/ Height
)。
所以我的想法是:
滚动项目列表,直到空列表(基本情况:列表中没有项目,因此我不会在AVL树中插入任何内容)
将列表的任何元素插入AVL树。
如果AVL树为空它有height=0
所以我创建了一个新的AVL树:
addavl(nil/0, Head, avl(nil/0, Head, nil/0)/H)
如果AVL树不为空,我会插入其中。
但它不起作用,可能是做这件事的错误方法。
有人可以帮助我吗?
答案 0 :(得分:2)
您正在尝试重新实施maplist/N
。
你有addavl(Tree, Element, NewTree)
。树已经采用T/Height
的形式。您必须以nil/0
开头。
buildTree(List,Tree):-
length(List, N),
length(L1, N), append(L1, [Tree], [nil/0 | L2]),
maplist( addavl, L1, List, L2).
(未经测试)。
关键是,使用addavl/3
作为给定的不透明谓词,不要重新审视它的定义。
两个列表L1
和L2
之间的逻辑变量共享(移位一个位置)用于安排累计结果从计算的一个步骤传递到下一个,表示nil/0
,直到在最后一步中构建完整的树Tree
。为方便起见,这是交易效率。您应该以直接递归样式重新实现它,特别是如果预期元素列表很长。
注释:是否使用maplist
或手动滚动直接递归解决方案,是语法问题。两种变体描述了相同的迭代计算过程,通过调用addavl
,使用先前调用的输出作为下一个的输入,逐步将元素添加到树中。一个常见的模式,例如不幸的是,在Haskell中,被一个名为的高阶程序捕获 - 惊喜! - iterate
。
(仅在更高级别的情况下才是这样。在具体实现中,如SWI Prolog,可以优化得比另一个好得多。使用列表,这里可能效率低于其他变量)。