【问题标题】:Prolog get elements in different lists with BFSProlog 使用 BFS 获取不同列表中的元素
【发布时间】:2011-01-06 00:54:11
【问题描述】:

我是 prolog 的新手,为了提高我的技能,我正在尝试做一些锻炼。 目前我被 BFS 卡住了,假设树是这样的:

[tree(tree(tree(nil,b,nil),a,tree(tree(nil,d,nil),c,tree(nil,e,nil)))]

在我的查询之后,我有类似的东西

X=a;

X=b;

X=c;

X=d;

X=e;

或者,至少:

X=a,b,c,d,e;

我想知道如何将结果按深度级别排序作为输出,例如:

X=[a];

X=[b,c];

X=[d,e];

或者,最好的情况是:

X=[ [a] , [b,c] , [d,e] ];

救命!

【问题讨论】:

  • 感谢蒂姆库珀纠正我的帖子,我很菜鸟^^"

标签: list tree prolog breadth-first-search


【解决方案1】:

我有一个解决方案,但不是特别有效。我将树实现为一组三个元素列表,例如 [Element, Left, Right],但它的工作方式应该相同。

% returns a list of nodes at the given level of the tree
level( [], _, [] ).
level( [Element, _, _], 0, [Element] ) :- !.
level( [_, Left, Right], N, Result ) :-
    NewN is N - 1,
    level( Left, NewN, LeftResult ),
    level( Right, NewN, RightResult ),
    append( LeftResult, RightResult, Result ).

% does a bfs, returning a list of lists, where each inner list
% is the nodes at a given level
bfs( Tree, Result ) :-
    level( Tree, 0, FirstLevel ), !,
    bfs( Tree, 1, FirstLevel, [], BFSReverse ),
    reverse( BFSReverse, Result ).
bfs( _, _, [], Accum, Accum ) :- !.
bfs( Tree, Num, LastLevel, Accum, Result ) :-
    level( Tree, Num, CurrentLevel ), !,
    NewNum is Num + 1,
    bfs( Tree, NewNum, CurrentLevel, [LastLevel|Accum], Result ).

应该可以在 O(n) 中做到这一点,但这是 O(n^2)。我开始研究另一种解决方案,它返回 O(n) 中每个元素的级别,但我不确定如何将该列表转换为 O(n) 中的解决方案格式而不诉诸断言/撤回。

【讨论】:

    【解决方案2】:

    更好的解决方案,这次是 O(n)。它仍然有点难看,因为我将实际的 BFS 与解决方案处理分开,但应该这样做。

    bfs2( Tree, Result ) :-
        bfs_queue( [[Tree, 0]], Queue ),
        queue_to_result( Queue, Result ).
    bfs_queue( [], [] ) :- !.
    bfs_queue( [[[],_]|Rest], RestResult ) :-
        !, bfs_queue( Rest, RestResult ).
    bfs_queue( [[[Element, Left, Right], Level]|Rest], [[Element,Level]|RestResult] ) :-
        NextLevel is Level + 1,
        append( Rest, [[Left, NextLevel], [Right, NextLevel]], NewQueue ), !,
        bfs_queue( NewQueue, RestResult ).
    
    process_level( [[Item, Level]|Rest], Level, [Item|RestResult], OutOfLevel ) :-
        !, process_level( Rest, Level, RestResult, OutOfLevel ).
    process_level( OutOfLevel, _, [], OutOfLevel ) :- !.
    queue_to_result( Queue, Result ) :-
        !, queue_to_result( Queue, 0, Result ).
    queue_to_result( [], _, [] ) :- !.
    queue_to_result( Queue, Level, [Current|Result] ) :-
        !, process_level( Queue, Level, Current, NewQueue ),
        NewLevel is Level + 1,
        queue_to_result( NewQueue, NewLevel, Result ).
    

    再次,我将树表示为三个元素列表。

    【讨论】:

    • 谢谢!!有用!!我正在学习“Learn Prolog Now”,但我认为这有点太简单了。还有什么书可以学习?
    • 这个版本的性能明显比 bfs/2 差。我用: n_tree(0, []) :- !. n_tree(N0, [N0,Left,Right]) :- N1 是 N0 - 1, n_tree(N1, Left), n_tree(N1, Right)。和查询: ?- between(0, 20, N), n_tree(N, T), time(bfs(T,Nodes)), false。两个版本。
    • 这个常数要高很多,因为它会生成列表的中间列表。此外,随着树变大,bfs/2 变得更糟;在处理级别 n 中,它必须遍历级别 0 到 n - 1,并且它不保存任何中间体。因此 O(n^2).
    • @RobCos Bro 能否请您提供运行此示例所需的查询。我已经尝试过并且失败了。我试过这个?- bfs2(tree(tree(nil,b,nil),a,tree(tree(nil,d,nil),c,tree(nil,e,nil))),X)。我是 prolog 的新手。所以无法找出我错过了什么!
    猜你喜欢
    • 2018-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多