如果Tree是一个满足堆属性和shape属性的堆,我需要一些帮助在prolog中编写谓词堆(Tree)成功:
我想使用2种不同的表示来编写2个谓词:
node(K,L,R)
代表一棵树,其中包含键K
(整数),左子树L
和右子树R
整数列表,从根到叶,从左到右
例如:
?- heap1(node(5, node(4, empty, empty), empty)).
true.
和
?- heap2([5, 4, 3, 2]).
true
?- heap2([7, 6, -1, -3, 5]).
true
?- heap2([]).
true
我目前对Prolog的知识非常有限,需要很多帮助来定义这些谓词。
答案 0 :(得分:2)
这个问题在最初发布之后就被删除了,因为OP并没有事先询问她问homework question这个问题。由于作业的截止日期已经过去,我决定取消删除这个答案。
我不是Prolog的大师,但我提出了一些想法。我认为heap1/1
比heap2/1
更容易实现,因为它的“树结构”更加明显。事实上,我要做的是实施heap1/1
,之后我将根据 heap2/1
实施heap1/1
。
heap1/1
empty
树是binary heap。至于node(K, L, R)
,它是一个堆,如果:
L
和R
是堆。L
和/或R
不是empty
,则其密钥小于或等于K
。L
的深度为 d ,则R
的深度为 d 或 d - 1 。所以需要做的是检查给定的二叉树是否满足这些属性。
给定node
,我们需要遍历它以了解它所代表的树的深度。因此,我们将根据谓词heap/1
定义heap/2
,其中第二个参数是树深度。最后我们不关心实际深度,因此我们定义:
heap1(H) :- heap1(H, _).
那么heap/2
呢?基本案例是empty
,这是一个深度为0
(或1
的堆,但这与我们的目的无关)。因此:
heap1(empty, 0).
对于node(K, L, R)
,我们必须递归。我们需要测试上面概述的堆属性并计算树深度H
。因此:
heap1(empty, 0).
heap1(node(K, L, R), H) :-
heap1(L, LH), heap1(R, RH),
(L = node(LK, _, _) *-> K @>= LK; true),
(R = node(RK, _, _) *-> K @>= RK; true),
(LH is RH; LH is RH + 1), H is LH + 1.
此代码使用SWI-Prolog的 soft cut (*->)/2
。此机制用于测试子树是否为非空,如果是,则验证其密钥是否小于或等于K
(使用(@>=)/2
)。谓词true/0
对应于其中一个子树 为空的情况。 (is)/2
用于比较子树的深度并计算整棵树的深度。
heap2/1
我假设heap2/1
应该检查它的唯一参数是否是表示存储为数组(或Ahnentafel list)的堆的列表。如果是,那么,假设零索引列表,索引 i 的节点的子节点在索引 2i + 1 和 2i + 2 < EM>
因此,父节点不一定存储在其子节点旁边。更具体地说,在列表中的 i 位置,我们需要跳过 i 或 i + 1 位置以到达子树的键。我们将定义一个谓词skipn/3
来帮助我们:
skipn(N, L, E) :- (length(F, N), append(F, E, L)) *-> true; E = [].
skipn(N, L, E)
成功,E
等于L
后,N
的{{1}}元素被剥离或如果{{ 1}}是空列表,而L
的长度不大于E
。此实施使用length/2
,append/3
和L
以及N
。
接下来:(*->)/2
的定义。我们将再次在辅助谓词的帮助下调用true/0
。如果列表heap2/1
(其头部位于可能更大的列表的位置heap2/3
)可以转换为二叉树heap2(H, N, T)
,则H
成功。 N
将使用初始索引T
调用heap2/1
,并验证生成的二叉树实际上是堆。因此:
heap2/3
好吧,我们快到了。在位置0
,左子树根的索引heap2(H) :- heap2(H, 0, T), heap1(T).
为N
。同样,LI
是右子树的根的索引。由于位置2 * N + 1
已经RI = 2 * N + 2
已跳过列表项,因此只需跳过N
和N
元素即可达到索引LI - N
和{{1} }, 分别。因此:
RI - N