Algoritmo de recorrido de entrada y salida de gráfico no dirigido

Algoritmo de recorrido de gráfico no dirigido

Recientemente, encontré un algoritmo que necesita atravesar un gráfico no dirigido. Necesita atravesar un cierto nodo del gráfico y encontrar todas las rutas hasta el final de cierto tipo de nodo. Se han encontrado muchos algoritmos en línea, pero ninguno de ellos es muy confiable. Más tarde encontré esto más confiable . Organizado de la siguiente manera:

Objetivo del algoritmo:

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

Idea de algoritmo:

  1. Ordene la relación entre los nodos y cree un conjunto para cada nodo, que almacena todos los nodos conectados directamente al nodo (sin incluir el nodo en sí);

  2. Defina dos puntos, uno es el nodo de inicio y el otro es el punto final. El problema de resolver todas las rutas entre los dos se puede descomponer en los siguientes subproblemas: Para cada nodo directamente conectado al nodo de inicio, resuélvalo a Todas las rutas en el punto final (la ruta no incluye el nodo de inicio) obtienen un conjunto de rutas y agregan estos conjuntos de rutas para obtener todas las rutas desde el nodo de inicio hasta el punto final; y así sucesivamente, la idea de recursividad se puede aplicar, de forma recursiva hasta el punto final , Si encuentra una ruta que desea, descargue e imprima, si encuentra un bucle, o encuentra un callejón sin salida, detenga la búsqueda de ruta y regrese;

  3. Use la pila para guardar los nodos en la ruta encontrada actualmente (no la ruta completa), y saque el nodo superior de la pila cada vez que encuentre la ruta completa; y saque la pila cuando encuentre la ruta desde el nodo superior de la pila que no puede continuar hacia abajo El nodo superior para lograr retroceder.

El código y la prueba son los siguientes:

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;
        }
    }

}

El algoritmo anterior se refiere al gráfico no dirigido de la siguiente manera:

[Imagen] El
Inserte la descripción de la imagen aquí
cálculo comienza desde 1 y busca una ruta con una salida de 8. La ruta no contiene 2 nodos.

El resultado es el siguiente

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

Supongo que te gusta

Origin blog.csdn.net/polixiaohai/article/details/103967580
Recomendado
Clasificación