无向图找出给定点包含的所有环(非递归算法)

实际背景:找出交易链中存在环的情况,目的是找出存在非法交易例如洗钱。
无向图
核心思想:
初始给定点所包含的全部路径

然后依次遍历树节点
当有回路时则为环,为空则删除该路径
注意:每次遍历时都会先删除以遍历的路径然后加上新的路径,例如(ab,abe,abg,abf)则ab删除新的abe,abg,abf存在集合中。当形成环时则存放在一个新的集合中,直到原来的集合中不存在元素,则执行完毕。
其中要考虑
1.回溯路径如:ab,ba
2.重复环:abgh,hgba
3.不包含指定节点的环 : ebf(图中未画出)
4.递归算法会影响性能,因为节点很多。

java代码实现:

package com.cy.graph;


import java.util.*;

/**
 * Search all rings in undirected graphs
 *
 * @author chenyue
 * @date 2019/10/26
 */
public class GraphSearchRing {
    public Integer numVertex;
    public Integer numEdge;
    public VertexNode[] vertexNodes;
    public static Integer firstNode;

    public GraphSearchRing(VertexNode[] vertexNodes) {
        this.numEdge = 0;
        this.numVertex = vertexNodes.length;
        this.vertexNodes = vertexNodes;
    }

    /**
     * Insert edge for node
     *
     * @param start
     * @param end
     */
    public void insertEdge(Integer start, Integer end) {
        VertexNode vertexNode = vertexNodes[start];
        EdgeNode edgeNode = new EdgeNode(end, null);

        EdgeNode firstEdgeNode = vertexNode.firstEdge;
        if (firstEdgeNode == null) {
            vertexNode.firstEdge = edgeNode;
        } else {
            edgeNode.next = firstEdgeNode;
            vertexNode.firstEdge = edgeNode;
        }
    }


    /**
     * Implementation of non-Recursive algorithm
     *
     * @param root
     */
    public void findRing(int root) {
        VertexNode node = vertexNodes[root];
        EdgeNode edge = node.firstEdge;
        List> allLinklist = new ArrayList<>();
        List nodeListResult = new ArrayList<>();
        // traversal firstnode reference edge
        while (edge != null) {
            if (vertexNodes[edge.adjvex].firstEdge != null) {
                ArrayList nodeList = new ArrayList();
                nodeList.add(firstNode);
                nodeList.add(edge.adjvex);
                allLinklist.add(nodeList);
            }
            edge = edge.next;
        }


        //eaxmple : ab abg,abgh,ebgha ,if last number equal firstnode(0) is ring
        while (true) {
            if (allLinklist.size() == 0) {
                break;
            }
            Iterator> iterator = allLinklist.listIterator();
            while (iterator.hasNext()) {
                ArrayList nodeList = iterator.next();
                int size = nodeList.size();
                //is ring
                if (nodeList.get(size - 1).equals(firstNode)) {
                    StringBuilder buffer = new StringBuilder();
                    Boolean exit = false;
                    for (Integer integer : nodeList) {
                        buffer.append(integer);
                    }
                    //distinct example: 0123  3210
                    for (String nodeaList : nodeListResult) {
                        if (nodeaList.equals(buffer.reverse().toString())) {
                            exit = true;
                        }
                    }
                    if (!exit) {
                        nodeListResult.add(buffer.toString());
                    }
                }

                // remove ab repalce abe,abg,abf
                iterator.remove();

                node = vertexNodes[nodeList.get(size - 1)];
                EdgeNode edgeNode = node.firstEdge;
                //traversal graph next edge
                while (edgeNode != null) {
                    //exxclude the same path. example : 10 01,ab ba
                    if (!edgeNode.adjvex.equals(nodeList.get(size - 2)) && !node.id.equals(firstNode)) {
                        ArrayList newNodeList = new ArrayList<>();
                        nodeList.forEach(t -> {
                            newNodeList.add(t);
                        });
                        //example :  abe abg
                        newNodeList.add(edgeNode.adjvex);
                        ((ListIterator>) iterator).add(newNodeList);
                    }
                    edgeNode = edgeNode.next;
                }
            }
        }

        nodeListResult.forEach(System.out::println);
    }


    /**
     * print graph structure for mid traversal
     *
     * @param graph
     */
    public static void printGraphStructure(GraphSearchRing graph, VertexNode[] vertexNodes) {
        for (int i = 0; i < graph.numVertex; i++) {
            VertexNode vertexNode = graph.vertexNodes[i];
            EdgeNode firstEdge = vertexNode.firstEdge;

            EdgeNode currentEdge = firstEdge;
            System.out.print(vertexNode.data + ":");
            while (currentEdge != null) {
                int vertexNodeIndex = currentEdge.adjvex;
                System.out.print("->" + vertexNodes[vertexNodeIndex].data);
                currentEdge = currentEdge.next;
            }
            System.out.println();
        }
    }

    public static void main(String[] args) {
        VertexNode[] vertexNodes = {
                new VertexNode(0, "a", null),
                new VertexNode(1, "b", null),
                new VertexNode(2, "c", null),
                new VertexNode(3, "d", null),
                new VertexNode(4, "e", null),
                new VertexNode(5, "f", null),
                new VertexNode(6, "g", null),
                new VertexNode(7, "h", null),
                new VertexNode(8, "i", null),
                new VertexNode(9, "j", null),

        };

        GraphSearchRing graph = new GraphSearchRing(vertexNodes);

        //Init edge equal 11
        graph.insertEdge(0, 8);
        graph.insertEdge(0, 9);
        graph.insertEdge(0, 2);
        graph.insertEdge(0, 7);
        graph.insertEdge(0, 1);
        graph.insertEdge(1, 4);
        graph.insertEdge(1, 5);
        graph.insertEdge(1, 6);
        graph.insertEdge(6, 7);
        graph.insertEdge(3, 9);
        graph.insertEdge(3, 4);

        //Undirected graph symmetry
        graph.insertEdge(8, 0);
        graph.insertEdge(9, 0);
        graph.insertEdge(2, 0);
        graph.insertEdge(7, 0);
        graph.insertEdge(1, 0);
        graph.insertEdge(4, 1);
        graph.insertEdge(5, 1);
        graph.insertEdge(6, 1);
        graph.insertEdge(7, 6);
        graph.insertEdge(9, 3);
        graph.insertEdge(4, 3);

        //Filter node for edge equal 1
        //in fact this method is not used
        /*for (int i = 0; i < vertexNodes.length; i++) {
            if (vertexNodes[i].firstEdge.next == null) {
                VertexNode vertexNode = vertexNodes[i];
                vertexNode.firstEdge = null;
                vertexNodes[i] = vertexNode;
            }
        }*/

        //0 equal a . we will find the firstnode is a.
        firstNode = 0;
        graph.findRing(firstNode);
    }
}



package com.cy.graph;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
/**
 * 表头节点
 *
 * @author cy
 * @date 2019/10/26
 */
public class VertexNode {
    /**
     * 结点序号
     * */
    public Integer id;
    /**
     * 结点信息
     * */
    public String data;
    /**
     * 第一条边
     * */
    public EdgeNode firstEdge;

}

package com.cy.graph;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
/**
 * 边节点
 *
 * @author cy
 * @date 2019/10/26
 */
public class EdgeNode {
    /**
     * 每条边的下一结点
     * */
    public Integer adjvex;
    /**
     * 下一个边结点
     * */
    public EdgeNode next;
}

输出:
01670
093410
07614390
也可以将输出的数字通过vertexNodes转化为字符

最后感谢我们架构师设计的算法还有他的图。hhhh~~~

你可能感兴趣的:(无向图找出给定点包含的所有环(非递归算法))