Undirected graph entrance and exit traversal algorithm

Undirected graph traversal algorithm

Recently, I encountered an algorithm that needs to traverse an undirected graph. It needs to traverse from a certain node of the graph and find all the paths to the end of a certain type of node. Many algorithms have been found online, but none of them are very reliable. Later I found this more reliable . Organized as follows:

Algorithm goal:

在一个无向连通图中求出两个给定点之间的所有路径;

Algorithm idea:

  1. Sort out the relationship between nodes, and create a set for each node, which stores all the nodes directly connected to the node (not including the node itself);

  2. Define two points, one is the starting node and the other is the end point. The problem of solving all paths between the two can be decomposed into the following sub-problems: For each node directly connected to the starting node, solve it to All paths at the end point (the path does not include the start node) get a path set. Add these path sets to get all the paths from the start node to the end point; and so on, the idea of ​​recursion can be applied, recursively until the end point , If you find a path you want, dump and print out; if you find a loop, or find a dead end, stop the path finding and return;

  3. Use the stack to save the nodes on the currently found path (not the complete path), and pop the top node of the stack every time the complete path is found; and pop the stack when it encounters the path from the top node of the stack that cannot continue downward The top node, so as to achieve backtracking.

The code and test are as follows:

import java.util.*;

public class test {
    
    
    /* 临时保存路径节点的栈 */
    public static Stack<Node> stack = new Stack<Node>();
    /* 存储路径的集合 */
    public static ArrayList<Node[]> sers = new ArrayList<>();

    /* 判断节点是否在栈中 */
    public static boolean isNodeInStack(Node node) {
    
    
        Iterator<Node> it = stack.iterator();
        while (it.hasNext()) {
    
    
            Node node1 = it.next();
            if (node == node1)
                return true;
        }
        return false;
    }

    /* 此时栈中的节点组成一条所求路径,转储并打印输出 */
    public static void showAndSavePath() {
    
    
        Node[] o = stack.stream().toArray(Node[]::new);
        for (int i = 0; i < o.length; i++) {
    
    
            Node nNode = o[i];

            if (i < (o.length - 1))
                System.out.print(nNode.getName() + "->");
            else
                System.out.print(nNode.getName());
        }
        sers.add(o); /* 转储 */
        System.out.println("\n");
    }

    /*
     * 寻找路径的方法
     * cNode: 当前的起始节点currentNode
     * pNode: 当前起始节点的上一节点previousNode
     * sNode: 最初的起始节点startNode
     * eNode: 终点endNode
     */
    public static boolean getPaths(Node cNode, Node pNode, Node sNode) {
    
    
        Node nNode = null;
        /* 如果符合条件判断说明出现环路,不能再顺着该路径继续寻路,返回false */
        if (cNode != null && pNode != null && cNode == pNode)
            return false;

        if (cNode != null) {
    
    
            int i = 0;
            /* 起始节点入栈 */
            stack.push(cNode);
            /* 如果该起始节点就是终点,说明找到一条路径 */
            //这里可以增加多个规则,比如不经过某些结点,某类结点标识出口,如果存在重复结点及路径的时候
            //可以通过记录已有路径的首位结点来过滤重复路径等。
            if (cNode.name.equalsIgnoreCase("node2")) return true;
            if (cNode.name.equalsIgnoreCase("node8")) {
    
    
                /* 转储并打印输出该路径,返回true */
                showAndSavePath();
                return true;
            }
            /* 如果不是,继续寻路 */
            else {
    
    
                /*
                 * 从与当前起始节点cNode有连接关系的节点集中按顺序遍历得到一个节点
                 * 作为下一次递归寻路时的起始节点
                 */
                nNode = cNode.getRelationNodes().get(i);
                while (nNode != null) {
    
    
                    /*
                     * 如果nNode是最初的起始节点或者nNode就是cNode的上一节点或者nNode已经在栈中 ,
                     * 说明产生环路 ,应重新在与当前起始节点有连接关系的节点集中寻找nNode
                     */
                    if (pNode != null && (nNode == sNode || nNode == pNode || isNodeInStack(nNode))) {
    
    
                        i++;
                        if (i >= cNode.getRelationNodes().size())
                            nNode = null;
                        else {
    
    
                            nNode = cNode.getRelationNodes().get(i);
                        }
                        continue;
                    }

                    /* 以nNode为新的起始节点,当前起始节点cNode为上一节点,递归调用寻路方法 */
                    if (getPaths(nNode, cNode, sNode))/* 递归调用 */ {
    
    
                        /* 如果找到一条路径,则弹出栈顶节点 */
                        stack.pop();
                    }
                    /* 继续在与cNode有连接关系的节点集中测试nNode */
                    i++;
                    if (i >= cNode.getRelationNodes().size())
                        nNode = null;
                    else
                        nNode = cNode.getRelationNodes().get(i);
                }
                /*
                 * 当遍历完所有与cNode有连接关系的节点后,
                 * 说明在以cNode为起始节点到终点的路径已经全部找到
                 */
                stack.pop();
                return false;
            }
        } else
            return false;
    }

    public static void main(String[] args) {
    
    
        /* 定义节点数组 */
        Node[] node = new Node[11];

        for (int i = 0; i < node.length; i++) {
    
    
            node[i] = new Node();
            node[i].setName("node" + (i + 1));
            node[i].id = i;
        }

        node[0].setRelationNodes(Arrays.asList(node[3], node[1], node[10]));
        node[1].setRelationNodes(Arrays.asList(node[0], node[2], node[3]));
        node[2].setRelationNodes(Arrays.asList(node[1], node[4], node[10]));
        node[3].setRelationNodes(Arrays.asList(node[0], node[1], node[5], node[8], node[10]));
        node[4].setRelationNodes(Arrays.asList(node[2], node[8], node[9]));
        node[5].setRelationNodes(Arrays.asList(node[3], node[6]));
        node[6].setRelationNodes(Arrays.asList(node[5], node[7], node[8]));
        node[7].setRelationNodes(Arrays.asList(node[6], node[8]));
        node[8].setRelationNodes(Arrays.asList(node[1], node[3], node[6], node[7], node[4], node[10]));
        node[9].setRelationNodes(Arrays.asList(node[4], node[10]));
        node[10].setRelationNodes(Arrays.asList(node[9]));

        /* 开始搜索所有路径 */
        getPaths(node[0], null, node[0]);
    }

    public static class Node {
    
    
        private Integer id;
        public String name = null;
        public List<Node> relationNodes = new ArrayList<Node>();

        public String getName() {
    
    
            return name;
        }

        public void setName(String name) {
    
    
            this.name = name;
        }

        public List<Node> getRelationNodes() {
    
    
            return relationNodes;
        }

        public void setRelationNodes(List<Node> relationNodes) {
    
    
            this.relationNodes = relationNodes;
        }
    }

}

The above algorithm refers to the undirected graph as follows:

[Picture] The
Insert picture description here
calculation starts from 1, and looks for a path with an exit of 8. The path does not contain 2 nodes.

The result is as follows

node1->node4->node6->node7->node8

node1->node4->node6->node7->node9->node8

node1->node4->node9->node7->node8

node1->node4->node9->node8

node1->node4->node11->node10->node5->node9->node7->node8

node1->node4->node11->node10->node5->node9->node8

node1->node11->node10->node5->node9->node4->node6->node7->node8

node1->node11->node10->node5->node9->node7->node8

node1->node11->node10->node5->node9->node8

Guess you like

Origin blog.csdn.net/polixiaohai/article/details/103967580