Data structure and algorithm (traversal of graphs and minimum spanning tree)

First language

Graph traversal

  • The traversal of the graph is similar to the traversal of the tree. We hope to visit the rest of the vertices in the graph starting from a vertex in the graph, and make each vertex be visited only once. This process is called the traversing graph (Traversing Graph).

Depth first traversal

  • Depth first traversal (Depth_First_Search), also known as depth first search, or DFS for short.
  • It starts from a certain vertex v in the graph, visits this vertex, and then starts from the unvisited neighboring points of v to traverse the graph in depth first, until all vertices in the graph that have paths connected to v are visited.

Code

  • Recursive implementation
/**
     * 对外公开的深度优先遍历
     */
    public void depthFirstSearch() {
    
    
        isVisited = new boolean[vertexSize];
        for (int i = 0; i < vertexSize; i++) {
    
    
            if (!isVisited[i]) {
    
    
                System.out.println("被访问到了:" + i + "顶点");
                depthFirstSearch(i);
            }
        }
        isVisited = new boolean[vertexSize];
    }
 /**
     * 图的深度优先遍历算法
     * @param i
     */
    private void depthFirstSearch(int i) {
    
    
        isVisited[i] = true;
        int w = getFirstNeighbor(i);
        while (w != -1) {
    
    
            if (!isVisited[w]) {
    
    
                //需要遍历该顶点
                System.out.println("被访问到了:" + w + "顶点");
                depthFirstSearch(w);
            }
            w = getNextNeighbor(i, w);
        }
    }
     /**
     * 获取某个顶点的第一个邻接点
     *
     * @param index
     * @return
     */
    public int getFirstNeighbor(int index) {
    
    
        for (int j = 0; j < vertexSize; j++) {
    
    
            if (matrix[index][j] > 0 && matrix[index][j] < MAX_WEIGHT) {
    
    
                return j;
            }
        }
        return -1;//无邻接点
    }
    /**
     * 根据前一个邻接点的下标来获取下一个邻接点
     *
     * @param v1 要找的顶点
     * @param v2 表示该顶点相对于那个邻接点去获取下一个邻接点
     * @return
     */
    public int getNextNeighbor(int v1, int v2) {
    
    
        for (int j = v2 + 1; j < vertexSize; j++) {
    
    
            if (matrix[v1][j] > 0 && matrix[v1][j] < MAX_WEIGHT) {
    
    
                return j;
            }
        }
        return -1;
    }
  • Stack implementation
public void dfs() {
    
    
        // 初始化所有的节点的访问标志
        for (int v = 0; v < visited.length; v++) {
    
    
            visited[v] = false;
        }
        Stack<Integer> stack = new Stack<Integer>();
        for (int i = 0; i < vexnum; i++) {
    
    
            if (visited[i] == false) {
    
    
                visited[i] = true;
                System.out.print(vertices[i] + " ");
                stack.push(i);
            }
            while (!stack.isEmpty()) {
    
    
                // 当前出栈的节点
                int k = stack.pop();
                for (int j = 0; j < vexnum; j++) {
    
    
                    // 如果是相邻的节点且没有访问过.
                    if (arcs[k][j] == 1 && visited[j] == false) {
    
    
                        visited[j] = true;
                        System.out.print(vertices[j] + " ");
                        stack.push(j);
                        // 这条路结束,返回上一个节点.
                         break;
                    }
                }
            }
        }       // 输出二维矩阵
        System.out.println();
        pritf(arcs);
    }
    /**
     * 输出邻接矩阵
     */
    public void pritf(int[][] arcs) {
    
    
        for (int i = 0; i < arcs.length; i++) {
    
    
            for (int j = 0; j < arcs[0].length; j++) {
    
    
                System.out.print(arcs[i][j] + "\t");
            }
            System.out.println();
        }
    }

Breadth first traversal

  • Breadth First Search, also known as Breadth First Search, or BFS for short.
  • Similar to the traversal of tree hierarchy, it is implemented using queues.

Code

public void broadFirstSearch() {
    
    
        isVisited = new boolean[vertexSize];
        for (int i = 0; i < vertexSize; i++) {
    
    
            if (!isVisited[i]) {
    
    
                broadFirstSearch(i);
            }
        }
    }
     /**
     * 实现广度优先遍历(队列)
     *
     * @param i
     */
    private void broadFirstSearch(int i) {
    
    
        int u, w;
        LinkedList<Integer> queue = new LinkedList<>();
        System.out.println("被访问到了:" + i + "顶点");
        isVisited[i] = true;
        queue.add(i);//第一次把v0加到队列
        while (!queue.isEmpty()) {
    
    
            u = queue.removeFirst();
            w=getFirstNeighbor(u);
            while (w!=-1){
    
    
                if (!isVisited[w]){
    
    
                    System.out.println("被访问到了:" + w + "顶点");
                    isVisited[w]=true;
                    queue.add(w);
                }
                w=getNextNeighbor(u,w);
            }
        }
    }

Minimum spanning tree

  • Suppose you are a telecommunications implementation engineer and you need to set up a communication network for nine villages in a town. The location of the village is roughly as shown in the figure, where Vo~V8 are villages, and the number connecting the villages represents the accessibility between the villages. The straight-line distance, for example, Vo to V1 is 10 kilometers (individually, such as Vo and V6, V6 and V8, V5 and V7, the unmeasured distance is because there are mountains or lakes and will not be considered). Your leader requires you to complete this task with minimal cost. What do you propose?
  • The spanning tree of a connected graph is a tiny connected subgraph that contains all the vertices in the graph, but only has n-1 edges that are enough to form a tree. We take the minimum cost spanning tree to construct the connected network. It is called the minimum spanning tree.
  • To find the minimum spanning tree of the connected network, there are two classic algorithms, Prim's algorithm and Kruskal's algorithm.

Code

  • Prim's Algorithm
   /**
     * prim 普里姆算法
     */
    public void prim(){
    
    
        int[] lowcost=new int[vertexSize];//最小代价顶点权值的数组,为0表示已经获取最小权值
        int[] adjvex=new int[vertexSize];//放顶点权值
        int min,minId,sum=0;
        for (int i=1;i<vertexSize;i++){
    
    
            lowcost[i]=matrix[0][i];
        }
        for (int i=1;i<vertexSize;i++){
    
    
            min=MAX_WEIGHT;
            minId=0;
            for (int j=1;j<vertexSize;j++){
    
    
                if (lowcost[j]<min&&lowcost[j]>0){
    
    
                    min=lowcost[j];
                    minId=j;
                }
            }
            System.out.println("顶点:"+adjvex[minId]+"权值:"+min);
            sum+=min;
            lowcost[minId]=0;
            for (int j=0;j<vertexSize;j++){
    
    
                if (lowcost[j]!=0&&matrix[minId][j]<lowcost[j]){
    
    
                    lowcost[j]=matrix[minId][j];
                    adjvex[j]=minId;
                }
            }
        }
        System.out.println("权值总和:"+sum);
    }
  • Kruskal Algorithm

First construct a subgraph with only n vertices and an empty edge set, and treat each vertex in the subgraph as the root node of each tree, and then
select the one with the smallest weight from the edge set E of the network Edge, if the two vertices of the edge belong to different trees, add it to the subgraph, that is, combine the two trees into one tree, otherwise, if the two vertices of the edge have fallen on the same tree , Is undesirable, and you should remove the edge with the smallest weight and try it again. And so on, until there is only one tree in the forest, that is, the subgraph contains n-1 edges.

/**
     * 克鲁斯卡尔算法最小生成树
     */
    public void miniSpanTreeKruskal(){
    
    
        int m,n,sum=0;
        int[] parent=new int[edgeSize];//神奇的数组,下标为起点,值为终点
        for (int i = 0; i < edgeSize; i++) {
    
    
            parent[i]=0;
        }
        for (int i = 0; i < edgeSize; i++) {
    
    
            n=find(parent,edges[i].begin);
            m=find(parent,edges[i].end);
            if (n!=m){
    
    
                parent[n]=m;
                System.out.println("起始顶点:"+edges[i].begin+"结束顶点:"+edges[i].end+"权值:"+edges[i].weight);
                sum+=edges[i].weight;
            }else {
    
    
                System.out.println("第"+i+"边回环了!");
            }
        }
        System.out.println("权值总和:"+sum);
    }

    /**
     * 将神奇数组进行查询获取非回环的值
     * @param parent
     * @param f
     * @return
     */
    private int find(int[] parent, int f) {
    
    
        while (parent[f]>0){
    
    
            System.out.println("找到起点:"+f);
            f=parent[f];
            System.out.println("找到终点:"+f);
        }
        return f;
    }
    public void createEdgeArray(){
    
    
        Edge edge0 = new Edge(4,7,7);
        Edge edge1 = new Edge(2,8,8);
        Edge edge2 = new Edge(0,1,10);
        Edge edge3 = new Edge(0,5,11);
        Edge edge4 = new Edge(1,8,12);
        Edge edge5 = new Edge(3,7,16);
        Edge edge6 = new Edge(1,6,16);
        Edge edge7 = new Edge(5,6,17);
        Edge edge8 = new Edge(1,2,18);
        Edge edge9 = new Edge(6,7,19);
        Edge edge10 = new Edge(3,4,20);
        Edge edge11 = new Edge(3,8,21);
        Edge edge12 = new Edge(2,3,22);
        Edge edge13 = new Edge(3,6,24);
        Edge edge14 = new Edge(4,5,26);
        edges[0] = edge0;
        edges[1] = edge1;
        edges[2] = edge2;
        edges[3] = edge3;
        edges[4] = edge4;
        edges[5] = edge5;
        edges[6] = edge6;
        edges[7] = edge7;
        edges[8] = edge8;
        edges[9] = edge9;
        edges[10] = edge10;
        edges[11] = edge11;
        edges[12] = edge12;
        edges[13] = edge13;
        edges[14] = edge14;
    }
    class Edge{
    
    
        private int begin;
        private int end;
        private int weight;

        public Edge(int begin, int end, int weight) {
    
    
            this.begin = begin;
            this.end = end;
            this.weight = weight;
        }

    }

Guess you like

Origin blog.csdn.net/yang_study_first/article/details/104392457