如何在JavaScript元素的层次结构中检测循环

时间:2019-03-25 13:28:39

标签: javascript arrays tree graph-theory

我有一个元素列表,每个元素都有一个ID和一个父ID。我想做的是检测此“层次结构”中是否存在循环,并显示哪个ID开始循环。

list = [
  {
    id: '1',
    parent: '2'
  },
  {
    id: '2',
    parent: '3'
  },
  {
    id: '3',
    parent: '4'
  },
    {
    //This id is causing the loop
    id: '4',
    parent: '1'
  }
]

我已经尝试过构建树,它在没有循环的情况下可以工作,但是在没有循环的情况下可以工作:

function treeify(list, idAttr, parentAttr, childrenAttr) {
    if (!idAttr) idAttr = 'id';
    if (!parentAttr) parentAttr = 'parent';
    if (!childrenAttr) childrenAttr = 'children';
    var treeList = [];
    var lookup = {};
    list.forEach(function(obj) {
        lookup[obj[idAttr]] = obj;
        obj[childrenAttr] = [];
    });
    list.forEach(function(obj) {
        if (obj[parentAttr] != null) {
            lookup[obj[parentAttr]][childrenAttr].push(obj);
        } else {
            treeList.push(obj);
        }
    });
    return treeList;
};

我也无法检测到何时出现循环。

我想返回导致循环的元素ID,以便我修复其背后的数据。

2 个答案:

答案 0 :(得分:1)

您可以应用白色-灰色-黑色着色来检测在访问其后代时被(重新)访问的节点(我已将您的图形简化为一系列父子对):

graph = [
    [2, 1],
    [3, 2],
    [1300023, 3],
    [1, 1300023],
];


colors = {}


function visit(vertex) {
    if (colors[vertex] === 'black') {
        // black = ok
        return; 
    }

    if (colors[vertex] === 'grey') {
        // grey = visited while its children are being visited
        // cycle!
        console.log('cycle', colors); 
        return; 
    }

    // mark as being visited
    colors[vertex] = 'grey';

    // visit children
    graph.forEach(edge => {
        if (edge[0] === vertex)
            visit(edge[1]);
    });

    // mark as visited and ok
    colors[vertex] = 'black'

}

visit(1)

这种方法的一个很好的例证:https://algorithms.tutorialhorizon.com/graph-detect-cycle-in-a-directed-graph-using-colors/

答案 1 :(得分:0)

您可以收集对象中的所有节点和子节点,并通过访问一组访问节点来过滤所有节点。

无限数组包含导致循环引用的所有节点。

~>
pod 'Appsee', '2.5.0'