List 二叉树的宽度优先-使用半文本表示法
我想计算列表是二叉树上的bfs顺序。此外,它应该在第二个侧面工作——对于列表,它可以找到树。List 二叉树的宽度优先-使用半文本表示法,list,prolog,dcg,dcg-semicontext,List,Prolog,Dcg,Dcg Semicontext,我想计算列表是二叉树上的bfs顺序。此外,它应该在第二个侧面工作——对于列表,它可以找到树。 你能给我一些提示吗,到目前为止我已经用过类似的东西,当然它不起作用 bfs(nil) --> []. bfs(t(X, L, R)), [X] --> bfs(L), bfs(R). 这就是如何使用(不使用半导体)和累加器来完成的: tree_bfss(T, Xs) :- phrase(bfs1([T]), Xs). bfs1([]) --> [].
你能给我一些提示吗,到目前为止我已经用过类似的东西,当然它不起作用
bfs(nil) --> [].
bfs(t(X, L, R)), [X] --> bfs(L), bfs(R).
这就是如何使用(不使用半导体)和累加器来完成的:
tree_bfss(T, Xs) :-
phrase(bfs1([T]), Xs).
bfs1([]) --> []. % done if level is empty
bfs1([X|Xs]) -->
step_(X, [], Ts), % single step
bfs0_(Xs, Ts). % process items in this level
bfs0_([], Ts) -->
bfs1(Ts). % process next level
bfs0_([X|Xs], Ts0) -->
step_(X, Ts0, Ts), % single step
bfs0_(Xs, Ts). % continue with this level
step_(nil, Ts, Ts) --> [].
step_(t(L,M,R), Ts, [R,L|Ts]) --> % push R and L to the next level
[M]. % take care of M right now
使用SICStus Prolog 4.3.2的示例查询:
| ?- tree_bfss(t(t(nil,1,t(nil,2,nil)),3,t(nil,4,nil)), Xs).
Xs = [3,4,1,2] ? ;
no
往另一个方向走怎么样
| ?- tree_bfss(T, [3,4,1,2]).
T = t(t(t(t(nil,2,nil),1,nil),4,nil),3,nil) ? ;
T = t(t(t(nil,1,t(nil,2,nil)),4,nil),3,nil) ? ;
T = t(t(nil,4,t(t(nil,2,nil),1,nil)),3,nil) ? ;
T = t(t(nil,4,t(nil,1,t(nil,2,nil))),3,nil) ? ;
T = t(t(t(nil,2,nil),4,t(nil,1,nil)),3,nil) ? ;
T = t(nil,3,t(t(t(nil,2,nil),1,nil),4,nil)) ? ;
T = t(nil,3,t(t(nil,1,t(nil,2,nil)),4,nil)) ? ;
T = t(nil,3,t(nil,4,t(t(nil,2,nil),1,nil))) ? ;
T = t(nil,3,t(nil,4,t(nil,1,t(nil,2,nil)))) ? ;
T = t(nil,3,t(t(nil,2,nil),4,t(nil,1,nil))) ? ;
T = t(t(nil,1,nil),3,t(t(nil,2,nil),4,nil)) ? ;
T = t(t(nil,1,nil),3,t(nil,4,t(nil,2,nil))) ? ;
T = t(t(t(nil,2,nil),1,nil),3,t(nil,4,nil)) ? ;
T = t(t(nil,1,t(nil,2,nil)),3,t(nil,4,nil)) ? ;
no
编辑
有用的意见建议澄清清单项目的顺序:
- 上述代码不保证每个树级别内的任何特定顺序
- 它确实确保第i级的所有项目出现在第(i+1)级的所有项目之前
(这使得实现稍微简单了一些。)看起来@repeat想出了一个不错的DCG解决方案。与此同时,我提出了一个“传统”的基于队列的解决方案,它是非DCG的:
bfs_tree_list(nil, []).
bfs_tree_list(Tree, List) :-
bfs_q_list([Tree], List).
bfs_q_list([], []).
bfs_q_list([t(X,L,R)|Qs], [X|Xs]) :-
enqueue(L, Qs, Q1),
enqueue(R, Q1, Q2),
bfs_q_list(Q2, Xs).
% "naive" enqueue using append
enqueue(nil, Q, Q).
enqueue(t(X,L,R), Q1, Q2) :- append(Q1, [t(X,L,R)], Q2).
这遵循我在评论中提供的链接中显示的方法。它还遵循严格的从左到右的遍历顺序,我相信这在二叉树遍历中是常规的。它比链接中的要简单一些,因为它们是用于更一般的图而不是二叉树。对上述情况的描述很简单:
(b) 将左侧和右侧节点排队
| ?- bfs_tree_list(t(3,t(1,nil,t(2,nil,nil)),t(4,nil,nil)), L).
L = [3,1,4,2]
(1 ms) yes
以及:
这里有一个修订版,它使用了差异列表,而不是
append/3
bfs_tree_list(nil, []).
bfs_tree_list(Tree, List) :-
bfs_q_list([Tree|T], T, List).
bfs_q_list(Q, T, []) :- Q == T, !.
bfs_q_list([t(X,L,R)|Qs], T, [X|Xs]) :-
[t(X,L,R)|Qs] \== T,
enqueue(L, T1, T),
enqueue(R, NewT, T1),
bfs_q_list(Qs, NewT, Xs).
enqueue(nil, Q, Q).
enqueue(t(X,L,R), T, [t(X,L,R)|T]).
你试过在谷歌上搜索“Prolog BFS”吗?你会得到的。这将比做DFS更复杂。一种方法是使用队列,其他语言在开发BFS方法时也使用队列。搜索列表中还有一个有趣的演示,它使用了其他技术。是的,我检查过了。尽管如此,请记住我的情况是特殊的-它是二叉树。你是指封闭列表还是开放列表?我是指如果你单击我的链接,在搜索结果列表中。:)事实上,处理二叉树并不会改变BFS技术本身。它只是改变了遍历的一些次要细节。事实上,这可能只是所示方法的特殊化。在搜索过程中有很多用于PROlog的BFS链接,我想至少其中一个可以专门做二叉树,但是一定有一些东西可以让你在那里找到更多的东西。鲍里斯。它让我感觉更自然:(1)它类似于图形表示,(2)命名
t/3
的参数(稍微)更容易:L
eft,M
iddle,R
light,我认为将二叉树节点的属性表示为“value,left,right”更常见。你的代码真的产生[3,4,1,2]
是为了那棵树吗?我认为正确的BFS遍历应该是[3,1,4,2]
。可能将步骤(t(L,M,R),Ts[R,L|Ts])
更改为步骤(t(L,M,R),Ts[L,R|Ts])
)@潜伏者。是的。我认为项目的顺序(在一个级别内)是未指定的,不一定是从左到右。。。起初,我有你提议的命令。但是代码变得简单了一点(通过使用累加器而不是第二个差异列表)。另一种选择是,可以使用reverse/2
如下:bfs0([],Ts0)-->reverse(Ts0,Ts),bfs1(Ts)。
但是,我认为这不是必需的。你能告诉我如何实现开放/差异列表排队吗?@HaskellFun我在我的答案中添加了这个版本。非常感谢@重复一遍!我认为我做得很好,因为它是“我发现正确地删除一个无用的选择点并不容易。”再次感谢您的建议。我在用这些术语思考一些事情。:)
bfs_tree_list(nil, []).
bfs_tree_list(Tree, List) :-
bfs_q_list([Tree|T], T, List).
bfs_q_list(Q, T, []) :- Q == T, !.
bfs_q_list([t(X,L,R)|Qs], T, [X|Xs]) :-
[t(X,L,R)|Qs] \== T,
enqueue(L, T1, T),
enqueue(R, NewT, T1),
bfs_q_list(Qs, NewT, Xs).
enqueue(nil, Q, Q).
enqueue(t(X,L,R), T, [t(X,L,R)|T]).