使用无重复列表的元组/对的Prolog队列

时间:2013-12-20 00:32:47

标签: prolog queue

我正在尝试实现一个元组/对的队列,以便与SWI-Prolog中的AI一起使用。目标是首先用数据填充结构,然后评估每个元素。每个唯一(X,Y)对应仅评估一次。

目前,问题是我的实现不是队列而是堆栈。函数dequeue也过早地评估为false。这是我正在使用的代码的简化部分。

:- dynamic([queue/1, destination/2]).

enqueue(X, Y):-
     retract(queue(List)),
     \+member((X, Y), List),
     assert(queue([(X, Y)|List])).
enqueue(_,_).

dequeue:-
   retract(queue([(X, Y)|List])),
   retractall(destination(_, _)),
   assert(queue(List)),
   assert(destination(X, Y)).

.........................下面的实际代码................... ..........

add_to_list_of_dest(X, Y):-
    retract(list_of_dest(Stuff)),
    \+member((X, Y), Stuff),
    assert(list_of_dest([(X, Y)|Stuff])),
    format("List of Dest Added : (~d, ", X),
    format("~d)~n", Y).
add_to_list_of_dest(X, Y):-
    format("Duplicate Element Not Added : (~d, ", X),
    format("~d)~n", Y).

choose_destination:-
    current_pos(X, Y),
    destination(DestX, DestY),
    \+(X = DestX),
    \+(Y = DestY), 
    format("Choosing Desination : Currently Travelling~n").
choose_destination:-
    retract(list_of_dest([(X, Y)|Stuff])),
    retractall(destination(_, _)),
    assert(list_of_dest(Stuff)),
    assert(destination(X, Y)),
    format("Choosing Desination : (~d, ", X),
    format("~d)~n", Y).

3 个答案:

答案 0 :(得分:2)

@ChristianF的答案很好(+1),虽然附加到列表的末尾对于大队列来说会变得很麻烦。众所周知的替代方案使用两个堆栈。这样做会给你O(1)插入和摊销O(1)弹出。技巧是具有输入堆栈和输出堆栈。假设输出堆栈的顺序正确,只需返回顶部项目,当它为非空时弹出。如果为空,则取出输入堆栈并将其反转到输出堆栈。

% empty_queue(-Queue) is det.
empty_queue(queue([], [])).

% enqueue(+Item, +Queue, -NewQueue) is det.
enqueue(Item, queue(InStack, OutStack), queue([Item|InStack], OutStack)).

% dequeue(+Queue, -Item, -NewQueue) is det.
%    Handle the case where the output stack is ready to be used.
dequeue(queue(InStack, [Top|OutStack]), Top, queue(InStack, OutStack)).
%    Handle the case where the input and output stacks must be swapped.
dequeue(queue(InStack, []), Top, OutStack) :-
    reverse(InStack, NewOutStack),
    dequeue(queue([], NewOutStack), Top, OutStack).

您可以利用Prolog的非确定性来制作具有两种调用约定的单个谓词。这使其与append/3

的工作方式更相似
% queue(+Item, +QueueWithoutItem, -QueueWithItem) is det.
queue(Item, QueueWithoutItem, QueueWithItem) :-
    nonvar(Item), nonvar(QueueWithoutItem),
    enqueue(Item, QueueWithoutItem, QueueWithItem).

% queue(-Item, -QueueWithoutItem, +QueueWithItem) is semidet.
queue(Item, QueueWithoutItem, QueueWithItem) :-
    nonvar(QueueWithItem),
    dequeue(QueueWithItem, Item, QueueWithoutItem).

答案 1 :(得分:1)

如果您知道列表,建立队列真的不难:

%% enqueue(+Queue, +Element, -NewQueue)
enqueue(L, E, L2) :- append(L, [E], L2).

%% dequeue(+Queue, -Element, -NewQueue)
dequeue([H|T], H, T).

使用示例:

?- enqueue([], (2,3), L), enqueue(L, (4,5), L2), dequeue(L2, _Ignore, L3).
L = [ (2, 3)],
L2 = [ (2, 3), (4, 5)],
_Ignore = (2, 3),
L3 = [ (4, 5)].

答案 2 :(得分:1)

您可以使用difference_list,它附加在O(1)中:

init_queue(U-U).

en_queue(Q, Elem, New_Q) :-     
    append_dl(Q, [Elem|U]-U, New_Q).

de_queue([H|T]-U, H, T-U).

check_queue(Elem, Q) :-
    Q = A-[],
    member(Elem, A).


append_dl(A-B, B-C, A-C).