I need some help writing a predicate heap(Tree) in prolog that succeeds if Tree is a heap that satisfies both the heap property and the shape property:
- The shape property: the tree is an almost compl开发者_开发技巧ete binary tree; that is, all levels of the tree, except possibly the last one (deepest) are fully filled, and, if the last level of the tree is not complete, the nodes of that level are filled from left to right.
- The heap property: each node is greater than or equal to each of its children according to some comparison predicate which is fixed for the entire data structure.
I would like to write 2 predicates using 2 different representations:
node(K,L,R)to represent a tree with keyK(an integer), left subtreeLand right subtreeRlist of integers, from the root to leaf, left to right
For example:
?- heap1(node(5, node(4, empty, empty), empty)).
true.
and
?- heap2([5, 4, 3, 2]).
true
?- heap2([7, 6, -1, -3, 5]).
true
?- heap2([]).
true
I currently have very limited knowledge of Prolog and need a lot of helps defining these predicates.
This question was deleted right after it was originally posted, because the OP was not upfront about the fact that she asked a homework question. As the due date for the assignment has since passed, I have decided to undelete this answer.
I'm not a Prolog guru, but I gave your question some thought. I think heap1/1 is easier to implement than heap2/1, because its "tree structure" is more apparent. In fact, what I will do is implement heap1/1, after which I'll implement heap2/1 in terms of heap1/1.
The tree implementation: heap1/1
The empty tree is a binary heap. As for node(K, L, R), it is a heap if:
LandRare heaps.- If
Land/orRare notempty, then their key is less than or equal toK. - If
Lhas depth d, thenRhas depth d or d - 1.
So what needs to be done, is to check whether a given binary tree satisfies those properties.
Given a
node, we will need to traverse it to know the depth of the tree it represents. Hence we will defineheap/1in terms of a predicateheap/2, in which the second argument is the tree depth. In the end we don't care about the actual depth, so we define:heap1(H) :- heap1(H, _).So what about
heap/2? The base case isempty, which is a heap with depth0(or1, but that is irrelevant for our purposes). Thus:heap1(empty, 0).For
node(K, L, R)we'll have to recurse. We need to test the heap properties outlined above and calculate the tree depthH. Thus: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.This code uses SWI-Prolog's soft cut
(*->)/2. This mechanism is used to test whether the subtrees are non-empty, and if so, to verify that their key is smaller or equal toK(using(@>=)/2). The predicatetrue/0corresponds to the situation in which one of the subtrees is empty.(is)/2is used to compare the depths of the subtrees and to calculate the depth of the whole tree.
The list implementation: heap2/1
I assume that heap2/1 is supposed to check whether its sole argument is a list representing a heap stored as an array (or Ahnentafel list). If so, then, assuming a zero-indexed list, the children of a node at index i are found at indices 2i + 1 and 2i + 2.
As a result, a parent node is not necessarily stored right next to its child nodes. More specifically, at position i in the list we'll need to skip i or i + 1 places to reach the keys of the subtrees. We'll define a predicate
skipn/3to help us with that:skipn(N, L, E) :- (length(F, N), append(F, E, L)) *-> true; E = [].skipn(N, L, E)succeeds ifEequalsLafter the firstNelements ofLhave been stripped or ifEis the empty list while the length ofLis not greater thanN. This implementation useslength/2,append/3and again(*->)/2andtrue/0.Next up: the definition of
heap2/1. Again we will call in the help of an auxiliary predicate, this timeheap2/3.heap2(H, N, T)succeeds if the listH, of which the head is at positionNof a possibly greater list, can be converted to a binary treeT.heap2/1will callheap2/3with initial index0and will verify that the resulting binary tree is in fact a heap. Thus:heap2(H) :- heap2(H, 0, T), heap1(T).Alright, we're almost there. At position
Nthe indexLIof the root of the left subtree is2 * N + 1. LikewiseRI = 2 * N + 2is the index of the root of the right subtree. Since at positionNalreadyNlist items have been skipped, onlyLI - NandRI - Nelements need to be skipped to reach indicesLIandRI, respectively. Thus:heap2([], _, empty). heap2([H|T], N, node(H, L, R)) :- LI is 2 * N + 1, RI is 2 * N + 2, LS is LI - N, RS is RI - N, skipn(LS, [H|T], LT), skipn(RS, [H|T], RT), heap2(LT, LI, L), heap2(RT, RI, R).
加载中,请稍侯......
精彩评论