如何提高在无向图中查找所有周期的性能

时间:2015-05-13 14:06:37

标签: javascript algorithm graph

我参考了问题Finding all cycles in undirected graphs。并写了一个javascript版本,但是我遇到了性能问题,我在chrome上运行,花了大约8秒,太长时间了,在我的无向图上只有16个顶点和33个边。这是代码:



<script>
    var graph = [[37,36], [37,168], [37,85], [37,2264], [37,3203], [36,85], [36,536], [36,5097], [85,168], [85,654], [85,755], [85,3607], [85,4021], [85,5097], [168,755], [536,4021], [536,5097], [536,5464], [536,6533], [654,3607], [654,4021], [654,5564], [654,6533], [755,2357], [755,3203], [755,3607], [2264,2357], [2264,3203], [2357,3203], [4021,5097], [5464,5564], [5464,6533], [5564,6533]];
    var cycles = [];

    function findAllCycles() {
        var i, j, len;

        var st1 = new Date().getTime();

        for (i = 0; i < graph.length; i++) {
            var edge = graph[i];
            for (j = 0; j < 2; j++) {
                findNewCycles( [edge[j]] );
            }
        }

        var st2 = new Date().getTime();
        console.log("time: " + (st2-st1));
    };

    function findNewCycles(path) {
        var startNode = path[0],
            nextNode;

        // visit each edge and each node of each edge
        for (var i = 0; i < graph.length; i++) {
            var edge = graph[i];
            for (var j = 0; j < 2; j++) {
                var node = edge[j];
                if (node === startNode) //  edge refers to our current node
                {
                    nextNode = edge[(j + 1) % 2];
                    if ( !visited(nextNode, path) ) { //  neighbor node not on path yet
                        //  explore extended path
                        findNewCycles( [nextNode].concat(path), graph, cycles );
                    }
                    else if ( (path.length > 2) && (nextNode === path[path.length - 1]) ) { //  cycle found
                        //var p = normalize(path);
                        //var inv = invert(p);
                        if ( isNew(path, cycles) ) {
                            cycles.push(path);
                        }
                    }
                }
            }
        }
    }

    // check if vertex n is contained in path
    function visited(node, path) {
        return (path.indexOf(node) !== -1);
    }

    function isNew(path, cycles) {
        for (var i = 0; i < cycles.length; i++) {
            if ( equal(path, cycles[i]) ) {
                return false;
            }
        }

        return true;
    }

    function equal(path1, path2) {
        if (path1.length !== path2.length) {
            return false;
        }

        for (var i = 0; i < path1.length; i++) {
            var node1 = path1[i];
            for (var j = 0; j < path2.length; j++) {
                var node2 = path2[j];
                if (node1 === node2) {
                    break;
                }
            }
            if (j === path2.length) {
                return false;
            }
        }

        return true;
    }

    findAllCycles();
    console.log(cycles);
</script>
&#13;
&#13;
&#13;

如何改善表现。

2 个答案:

答案 0 :(得分:0)

我认为你可以尝试不同的方式。

您可以为每个节点计算它的深度。如果你来到一个已经有深度的节点,那么你就有了一个周期。

该算法将在O(n)中,其中n是节点的数量。它应该快得多。

如果你不关心深度,你可以“标记”节点。

答案 1 :(得分:0)

我认为问题不在于算法的实现。这个图表看起来很复杂,显然总共有3930个周期!包括39个无弦循环加上带有和弦的3891个循环(其中包括较小的循环)。

enter image description here

这类似于&#34;多少个方块&#34;问题,它加起来的速度可能会令人惊讶。

enter image description here

如果您只对无弦循环感兴趣,您可以进行显着优化。

(旁注:等于函数似乎过于复杂,但这可能不会对性能产生显着影响)

function pathIsEqual(path1, path2) {

    if (path1.length !== path2.length) {
        return false
    }

    for(var i = path1.length; i--;) {
        if(path1[i] !== path2[i]){
            return false
        }
    }

    return true;
}