我正在尝试制作一个搜索并返回xQuery中图形中两个节点之间路径的算法,到目前为止它只返回一个节点和它的邻接节点.
首先,我应该明确图形是一个有向图,每个节点可以有零个,一个或多个原点,在 XML中,一个节点只有到它原点的链接但不是它的后续节点
首先,我应该明确图形是一个有向图,每个节点可以有零个,一个或多个原点,在 XML中,一个节点只有到它原点的链接但不是它的后续节点
这是一些节点及其XML的示例
<node> <id> 123-456-789</id> <name> something </name> <Links> <Link> <origin></origin> </Link> <Links> <node> <id> 245-678-901</id> <name> node 2</name> <Links> <Link> <origin> 123-456-789 </origin> </Link> <Links> <node> <id> xxx-xxx-xxx</id> <name> node 3</name> <Links> <Link> <origin> 123-456-789 </origin> </Link> <Links> <node> <id> 234-546-768</id> <name> node 4</name> <Links> <Link> <origin> 245-678-901</origin> </Link> <Links>
从那个XML我想得到从节点1到节点4的路径(node1-> node2-> node4)
但无论我尝试做什么,只会给我node1-node2和node3但不是node4
另一件事是我想选择一个不直接的路径,我的意思是,如果我想要node5和node7之间的路径,但node5和node7都指向node6
我已经尝试将这个python代码改编为xquery
def BFS(graph,start,end,q): temp_path = [start] q.enqueue(temp_path) while q.IsEmpty() == False: tmp_path = q.dequeue() last_node = tmp_path[len(tmp_path)-1] print tmp_path if last_node == end: print "VALID_PATH : ",tmp_path for link_node in graph[last_node]: if link_node not in tmp_path: new_path = [] new_path = tmp_path + [link_node] q.enqueue(new_path)
(代码不是我的,它属于它在this activestate page的合法编码器)
这是我试图做的:
declare function local:BFS($graph as element()*,$ini_node as element(Node)*,$end_node as element(Node)*) as element()* { let $seq := $ini_node let $queue := ($seq) for $item in $queue return if ( count($queue) > 0) then let $seq := remove($queue,count($queue)) let $last := $seq[last()] return if (deep-equal($last,$end_node)) then $seq else for $node in $graph[contains(.,$graph/id[contains(.,$last/Links/Link/origin/text())])] (: what i've tried was to get the graph nodes which id is equal to the origins of the last node :) return if(not(functx:is-node-in-sequence-deep-equal($node,$seq))) then let $new_path:= () let $new_path:= insert-before($seq,count($seq)+1,$node) let $queue := insert-before($queue,1,$new_path) return $queue else () else () };
解决方法
XQuery和Python之间的根本区别在于XQuery是一个
functional programming language.这意味着之后不能修改绑定到变量的值.在你的函数local:BFS(…)例如,你不能在循环中改变$queue的值,你要做的就是创建一个新的变量$queue,它会遮蔽外部的变量.
为了使其工作,您可以将外部循环编写为recursive function,而不是将当前队列作为参数.然后,循环的每次迭代都是使用更新版本的队列调用函数:
declare function local:BFS($graph,$queue,$steps,$end) { if(empty($queue)) then error(xs:QName('local:NOTFOUND'),'No path found.') else ( let $curr := $queue[1],$rest-queue := $queue[position() > 1] return ( if($curr eq $end) then local:result($steps,$end) else ( let $successors := $graph//node[Links/Link/origin = $curr and not($steps/@to = id)]/id/string() let $new-steps := for $succ in $successors return <edge from="{$curr}" to="{$succ}" /> return local:BFS( $graph,($rest-queue,$successors),($steps,$new-steps),$end ) ) ) ) };
declare function local:BFS($graph,$start,$end) { local:BFS($graph,<edge to="{$start}" />,$end) };
所有使用的边缘都以$步骤存储.为了在找到目的地后重建路径,我们可以向后遍历它们直到找到初始边缘:
declare function local:result($steps,$dest) { let $pred := $steps[@to = $dest]/@from/string() return if(exists($pred)) then (local:result($steps,$pred),$dest) else $dest };
如果您担心性能,XQuery序列可能不是用作队列的最佳数据结构.关于用于查找的XML片段也可以这样说.因此,如果您可以访问XQuery 3.0处理器,您可以查看我在https://github.com/LeoWoerteler/xq-modules写的一些(至少是渐近的)更高效的数据结构.我甚至以Dijkstra’s algorithm为例.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。