javascript - JS中的自定义排序/路径查找
问题描述
我正在尝试制定一些排序/路径查找算法。作为起点,我总是有以下格式的开始 ID 和完成 ID(开始 + 最后一个节点的 ID):
{"START_ID": "1z2x", "FINISH_ID":"cc2v"}
下一部分是我的对象(边)要排序/找到路径的数组。每个对象的构造方式如下:
{"ID_FROM": "1z2x", "ID_TO": "wdf3"}
如您所见,每个对象都有起始节点和结束节点。因为我总是知道整个路径的开始节点和完成节点,所以我想编写路径。
例子:
开始 + 结束节点:
{"START_ID": "123v", "FINISH_ID":"8s6h"}
带边的数组:
[{"ID_FROM":"123v", "ID_TO":"985j"}, {"ID_FROM":"13kj", "ID_TO":"plnx"}, {"ID_FROM":"985j", "ID_TO":"13kj"}, {"ID_FROM":"7777", "ID_TO":"8s6h"}, {"ID_FROM":"plnx", "ID_TO":"7777"}]
从上面我想收到的路径是:
[{"ID_FROM":"123v", "ID_TO":"985j"}, {"ID_FROM":"985j", "ID_TO":"13kj"}, {"ID_FROM":"13kj", "ID_TO":"plnx"}, {"ID_FROM":"plnx", "ID_TO":"7777"}, {"ID_FROM":"7777", "ID_TO":"8s6h"}]
此外,可以有多个对象指向同一条边(它们应该在以下索引中),例如:
[{"ID_FROM":"123v", "ID_TO":"985j"}, {"ID_FROM":"13kj", "ID_TO":"plnx"}, {"ID_FROM":"985j", "ID_TO":"13kj"}, {"ID_FROM":"7777", "ID_TO":"8s6h"}, {"ID_FROM":"13kj", "ID_TO":"plnx"}, {"ID_FROM":"plnx", "ID_TO":"7777"}]
其路径将是:
[{"ID_FROM":"123v", "ID_TO":"985j"}, {"ID_FROM":"985j", "ID_TO":"13kj"}, {"ID_FROM":"13kj", "ID_TO":"plnx"},, {"ID_FROM":"13kj", "ID_TO":"plnx"}, {"ID_FROM":"plnx", "ID_TO":"7777"}, {"ID_FROM":"7777", "ID_TO":"8s6h"}]
一些限制/信息: -> 开始和结束节点始终是已知的 -> 边数可以从 2 到 10 不等 -> 可以有多个对象指向具有相同的 ID_FROM 和 ID_TO <- 它们不是重复的,应该是在以下职位
如果有人可以帮助我,我将不胜感激。
最好的问候,并在此先感谢您!垫
编辑:
我想建立一种可以去 ID1 -> ID2 -> ID3 <- ID4 的方式。假设我仍然知道开始和结束(ID1 和 ID4)。
例子:
[{"ID_FROM":"123v", "ID_TO":"985j"}, {"ID_FROM":"13kj", "ID_TO":"plnx"}, {"ID_FROM":"985j", "ID_TO":"13kj"}, {"ID_FROM":"8542", "ID_TO":"13kj"}]
在 START_ID = 123v 和 FINISH_ID = 8542 的情况下,路径应如下所示:
[{"ID_FROM":"123v", "ID_TO":"985j"}, {"ID_FROM":"985j", "ID_TO":"13kj"}, {"ID_FROM":"13kj", "ID_TO":"plnx"}, {"ID_FROM":"8542", "ID_TO":"plnx"}]
解决方案
使用简单的DFS算法,您可以找到一条路径(如果存在)(不一定是最短的)
function recursive_DFS(nodes, El, head, finish){
if(head === finish){
nodes.push(head)
return nodes;
}else{
nodes.push(head)
for(const next of (El[head] || [])){
t = recursive_DFS(nodes, El, next, finish)
if(t) return t;
}
nodes.pop(head)
}
}
// just make sure to produce the output in the format you want
function nodes_to_edges(nodes){
edges = []
for(let i = 1; i < nodes.length; ++i){
edges.push({ID_FROM: nodes[i-1], ID_TO: nodes[i]})
}
return edges;
}
function find_route(path, E){
El = {}
// make it easier to lookup afterwards
for(const {ID_FROM, ID_TO} of E){
if(!El[ID_FROM]) El[ID_FROM] = [ID_TO]
else El[ID_FROM].push(ID_TO)
}
return nodes_to_edges(recursive_DFS([], El, path.START_ID, path.FINISH_ID));
}
测试:
console.log(find_route(
{"START_ID": "123v", "FINISH_ID":"8s6h"},
[{"ID_FROM":"123v", "ID_TO":"985j"}, {"ID_FROM":"13kj", "ID_TO":"plnx"},
{"ID_FROM":"985j", "ID_TO":"13kj"}, {"ID_FROM":"7777", "ID_TO":"8s6h"},
{"ID_FROM":"plnx", "ID_TO":"7777"}]))
如果您对最佳性能感兴趣,您可能希望将递归 DFS 替换为迭代版本。如果您想确保找到最短路径,您可以使用BFS代替,但这需要先进先出而不是后进先出数据结构。
function annotate_paths(origin, El, head){
for(const next of (El[head] || [])){
if(!origin[next]){
// keep track of where it comes from
origin[next] = head;
t = annotate_paths(origin, El, next)
}
}
}
// just make sure to produce the output in the format you want
function reconstruct(origin, node, START){
edges = []
prevNode = node;
while(origin[node] !== START){
const prevNode = node;
node = origin[node];
edges.push({ID_FROM: node, ID_TO: prevNode})
}
return edges.reverse();
}
function find_route(path, E){
El = {}
// make it easier to lookup afterwards
for(const {ID_FROM, ID_TO} of E){
if(!El[ID_FROM]) El[ID_FROM] = [ID_TO]
else El[ID_FROM].push(ID_TO)
}
const {START_ID, FINISH_ID} = path;
const START = {}
origin1 = {}
origin2 = {}
origin1[START_ID] = START;
origin2[FINISH_ID] = START;
annotate_paths(origin1, El, START_ID)
annotate_paths(origin2, El, FINISH_ID)
for(const meetAt in origin1){
if(origin2[meetAt]){
path1 = reconstruct(origin1, meetAt, START) // Path from ID_FROM to meeting node
path2 = reconstruct(origin2, meetAt, START) // Path from ID_TO to the meeting node
return [...path1, ...path2.reverse()]
}
}
return null;
}
// Original question
console.log(find_route(
{"START_ID": "123v", "FINISH_ID":"8s6h"},
[
{"ID_FROM":"123v", "ID_TO":"985j"},
{"ID_FROM":"13kj", "ID_TO":"plnx"},
{"ID_FROM":"985j", "ID_TO":"13kj"},
{"ID_FROM":"7777", "ID_TO":"8s6h"},
{"ID_FROM":"plnx", "ID_TO":"7777"}
]))
// Updated question
console.log(find_route(
{
START_ID: '123v',
FINISH_ID: '8542'
},
[
{"ID_FROM":"123v", "ID_TO":"985j"},
{"ID_FROM":"13kj", "ID_TO":"plnx"},
{"ID_FROM":"985j", "ID_TO":"13kj"},
{"ID_FROM":"8542", "ID_TO":"13kj"}
]))
推荐阅读
- python - 附加不同维度的numpy数组
- azure - Azure 和访问控制的最佳实践
- r - 更改弹性表中的单元格值
- jquery - `display:inline-block` CSS 属性的问题
- python - matplotlib - 如果有多个事件处理程序,你可以设置优先级吗?
- android - 无法在 Java 中调用 Android 应用程序的 Cucumber 测试
- r - Rmarkdown - 重复的目录(目录)
- c++ - 为什么文字和临时变量不是左值?
- java - StringUtils.isBlank 方法上的 NumberFormatException
- html - 车身左右垂直之字形边框