zoukankan      html  css  js  c++  java
  • 【原创】Java与数据结构(下篇:图)

    1. 有向图的BFS和DFS

    package graph;
    
    import java.util.ArrayDeque;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 有向图的表示和遍历 <br>
     * 邻接矩阵和邻接表表示法和BFS/DFS
     * 
     * @author yinger
     */
    public class DirectedGraphTraverse {
    
        public static void main(String[] args) {
            // matrix for graph --- condition:graph is directed graph
            int[][] adjustMatrix = new int[][] { { 0, 1, 1, 1, 1, 0 }, { 0, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 1, 0 },
                    { 1, 0, 0, 0, 1, 0 }, { 0, 0, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0 } };
            System.out.println("Adjust link table:");
            linkTable(adjustMatrix);
            System.out.println("BFS for adjust matrix:");
            bfs(adjustMatrix);//0  1  2  3  4  5
            System.out.println();
            System.out.println("DFS for adjust matrix:");
            dfs(adjustMatrix);//0  1  4  3  2  5 
        }
    
        // adjust link table
        private static void linkTable(int[][] adjustMatrix) {
            int nodeSum = adjustMatrix.length;
            GraphNode[] linkTable = new GraphNode[nodeSum];
            for (int i = 0; i < nodeSum; i++) {// init table
                linkTable[i] = new GraphNode(i);
            }
            for (int j = 0; j < nodeSum; j++) {// modify table
                for (int k = 0; k < nodeSum; k++) {
                    if (adjustMatrix[j][k] == 1) {// edge exist
                        linkTable[j].linkNodes.add(linkTable[k]);
                    }
                }
            }
            for (int i = 0; i < nodeSum; i++) {// iterator
                System.out.print("Node: " + i + "\tLinkTable: ");
                for (GraphNode graphNode : linkTable[i].linkNodes) {
                    System.out.print(graphNode.id + "  ");
                }
                System.out.println();
            }
        }
    
        // graph matrix dfs:not recursive
        private static void dfs(int[][] adjustMatrix) {
            int nodeSum = adjustMatrix.length;
            int[] visit = new int[nodeSum];// visit[i] = 1 means the node i has been visited
            ArrayDeque<GraphNode> deque = new ArrayDeque<GraphNode>();
            for (int i = 0; i < nodeSum; i++) {// make sure all the node has been visited,include the lonely node
                if (visit[i] == 0) {
                    GraphNode current = new GraphNode(i);
                    deque.addLast(current);
                    while ((current = deque.pollLast()) != null) {// remove the last one
                        visit(current);
                        visit[current.id] = 1;
                        for (int j = 0; j < nodeSum; j++) {
                            if (adjustMatrix[current.id][j] == 1 && visit[j] == 0) {// adjust to current node and not visit
                                deque.addLast(new GraphNode(j));// when in stack,same node will not insert twice!
                                break;// insert only one node!
                            }
                        }
                    }
                }
            }
        }
    
        // graph matrix bfs:not recursive
        private static void bfs(int[][] adjustMatrix) {
            int nodeSum = adjustMatrix.length;
            int[] visit = new int[nodeSum];// visit[i] = 1 means the node i has been visited
            ArrayDeque<GraphNode> deque = new ArrayDeque<GraphNode>();
            for (int i = 0; i < nodeSum; i++) {// make sure all the node has been visited,include the lonely node
                if (visit[i] == 0) {
                    GraphNode current = new GraphNode(i);
                    deque.addLast(current);
                    while ((current = deque.pollFirst()) != null) {
                        if (visit[current.id] == 0) {// insure the node has not visit
                            visit(current);
                            visit[current.id] = 1;
                            for (int j = 0; j < nodeSum; j++) {// insert the nodes adjust current node into the deque
                                if (adjustMatrix[current.id][j] == 1 && visit[j] == 0) {// if node in the deque,but not
                                    deque.addLast(new GraphNode(j));// visit,so it maybe insert many times!
                                }
                            }
                        }
                    }
                }
            }
        }
    
        private static void visit(GraphNode node) {
            System.out.print(node.id + "  ");
        }
    
    }
    
    class GraphNode {
        int id;// node id
        List<GraphNode> linkNodes = new ArrayList<GraphNode>();
    
        public GraphNode(int id) {
            this.id = id;
        }
    
    }
    
    // result
    // Adjust link table:
    // Node: 0 LinkTable: 1 2 3 4
    // Node: 1 LinkTable: 4
    // Node: 2 LinkTable: 4
    // Node: 3 LinkTable: 0 4
    // Node: 4 LinkTable: 3
    // Node: 5 LinkTable:
    // BFS for adjust matrix:
    // 0 1 2 3 4 5
    // DFS for adjust matrix:
    // 0 1 4 3 2 5

    2. 无向连通图的最小生成树算法 Prime 和 Kruskal算法

    package graph;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 无向连通图的最小生成树算法<br>
     * Prime算法和Kruskal算法
     * 
     * @author yinger
     */
    public class UndirectedGraphMST {
    
        public static final int INFINITE = 1000;
    
        public static void main(String[] args) {
            int[][] costMatrix = new int[][] { { 0, 34, 46, INFINITE, INFINITE, 19 },
                    { 34, 0, INFINITE, INFINITE, 12, INFINITE }, { 46, INFINITE, 0, 17, INFINITE, 25 },
                    { INFINITE, INFINITE, 17, 0, 38, 25 }, { INFINITE, 12, INFINITE, 38, 0, 26 },
                    { 19, INFINITE, 25, 25, 26, 0 } };
            System.out.println("Prime Algorithm:");
            prime(costMatrix);
            System.out.println("Kruskal Algorithm:");
            kruskal(costMatrix);
        }
    
        // prime algorithm time: O(n^2)
        private static void prime(int[][] costMatrix) {
            int nodeSum = costMatrix.length;
            int[] lowCost = new int[nodeSum];// lowCost[i] = j means the min cost of node i to the tree is j
            int[] lowNode = new int[nodeSum];// lowNode[i] = j means node i into tree via node j
            int[] visit = new int[nodeSum];// is the node has been included,it uses to avoid circle!
            for (int i = 0; i < nodeSum; i++) {// init lowcost according to costMatrix
                lowCost[i] = costMatrix[0][i];
                lowNode[i] = 0;// init
            }
            visit[0] = 1;// visit node 0,the source
            int minNode, minCost;// current node which cost is min
            for (int k = 1; k < nodeSum; k++) {// total time:nodeSum -1
                minNode = 0;
                minCost = INFINITE;
                for (int i = 0; i < nodeSum; i++) {
                    if (visit[i] == 0 && lowCost[i] < minCost) {// not visit and lowcost is lower
                        minNode = i;
                        minCost = lowCost[i];
                    }
                }
                visit[minNode] = 1;// visit the minNode
                System.out.println(minCost + " (" + lowNode[minNode] + " -> " + minNode + ")");
                for (int i = 0; i < nodeSum; i++) {// modify lowcost because of the newly insert node minNode
                    if (costMatrix[minNode][i] < lowCost[i]) {
                        lowCost[i] = costMatrix[minNode][i];
                        lowNode[i] = minNode;
                    }
                }
            }
        }
    
        // kruskal algorithm: time: O(e*log(e))
        private static void kruskal(int[][] costMatrix) {
            int nodeSum = costMatrix.length;
            // KruskalEdge[] edges = new KruskalEdge[];//array is not useful,because the number of edge is not sure
            ArrayList<KruskalEdge> edgeList = new ArrayList<KruskalEdge>();
            for (int i = 0; i < nodeSum; i++) {// init and sort the edge list
                for (int j = i + 1; j < nodeSum; j++) {// j>i
                    if (costMatrix[i][j] != INFINITE) {
                        insertNewEdge(edgeList, new KruskalEdge(i, j, costMatrix[i][j]));
                    }
                }
            }
            // for (KruskalEdge kruskalEdge : edgeList) {//print edge list in increse orders
            // System.out.println(kruskalEdge.start + " -> " + kruskalEdge.end + " " + kruskalEdge.weight);
            // }
            // int[] visit = new int[nodeSum];// is the node visit? to avoid the circle//wrong method!
            List<KruskalTree> treeList = new ArrayList<KruskalTree>();
            for (int i = 0; i < nodeSum; i++) {// init tree:only self node in the tree
                KruskalTree tree = new KruskalTree(i);
                tree.treeNodes.add(new KruskalNode(i));
                treeList.add(tree);
            }
            KruskalEdge edge;
            KruskalTree startTree, endTree;
            while (treeList.size() > 1) {
                edge = edgeList.remove(0);
                startTree = findTree(treeList, edge.start);
                endTree = findTree(treeList, edge.end);
                // System.out.println(edge.start + "  " + edge.end + "  " + startTree.root + "  " + endTree.root);//test
                if (startTree.root == endTree.root) {// the two nodes from the same tree,
                    continue;// circle will appear if the edge is inserted!
                }// else,the two trees are not same,then move tree nodes from one to another
                if (startTree.treeNodes.size() < endTree.treeNodes.size()) {// from the less one to the more one
                    for (int i = 0; i < startTree.treeNodes.size(); i++) {
                        endTree.treeNodes.add(startTree.treeNodes.get(i));
                    }
                    treeList.remove(startTree);
                } else {
                    for (int i = 0; i < endTree.treeNodes.size(); i++) {
                        startTree.treeNodes.add(endTree.treeNodes.get(i));
                    }
                    treeList.remove(endTree);
                }
                System.out.println(edge.weight + " (" + edge.start + " -> " + edge.end + ")");
            }
        }
    
        private static KruskalTree findTree(List<KruskalTree> treeList, int key) {// find the giving node in which tree
            for (int i = 0; i < treeList.size(); i++) {
                List<KruskalNode> treeNodes = treeList.get(i).treeNodes;
                for (KruskalNode kruskalNode : treeNodes) {
                    if (kruskalNode.id == key) {
                        return treeList.get(i);
                    }
                }
            }
            return treeList.get(0);// default!
        }
    
        private static void insertNewEdge(ArrayList<KruskalEdge> edgeList, KruskalEdge kruskalEdge) {// using insert sort
            edgeList.add(kruskalEdge);// first insert to make size++
            int low = 0;
            int high = edgeList.size() - 2;// attention here: the last one not in! otherwise,exception will appear
            int mid;
            while (low <= high) {// find position:low
                mid = (low + high) / 2;
                if (edgeList.get(mid).weight > kruskalEdge.weight) {
                    high = mid - 1;
                } else {
                    low = mid + 1;
                }
            }
            for (int i = edgeList.size() - 1; i > low; i--) {// move back
                edgeList.set(i, edgeList.get(i - 1));
            }
            edgeList.set(low, kruskalEdge);
        }
    }
    
    class KruskalEdge {// edge in kruskal algorithm
        int start;
        int end;
        int weight;
    
        public KruskalEdge(int start, int end, int weight) {
            this.start = start;
            this.end = end;
            this.weight = weight;
        }
    
    }
    
    class KruskalNode {// node in kruskal algorithm
    
        int id;
    
        public KruskalNode(int id) {
            this.id = id;
        }
    
    }
    
    class KruskalTree {// tree in kruskal algorithm
    
        public KruskalTree(int root) {
            this.root = root;
        }
    
        int root;// root is the first node in the tree,in order to identify a tree
        List<KruskalNode> treeNodes = new ArrayList<KruskalNode>();// kruskal graph linked part:tree,node id saved!
    
    }
    
    // result:
    // Prime Algorithm:
    // 19 (0 -> 5)
    // 25 (5 -> 2)
    // 17 (2 -> 3)
    // 26 (5 -> 4)
    // 12 (4 -> 1)
    // Kruskal Algorithm:
    // 12 (1 -> 4)
    // 17 (2 -> 3)
    // 19 (0 -> 5)
    // 25 (2 -> 5)
    // 26 (4 -> 5)

    3. 最短路径算法 Dijkstra 和 Floyd算法

    package graph;
    
    /**
     * 带权有向图的单源最短路径算法Dijkstra和任意两个顶点最短路径算法Floyd
     * 
     * @author yinger
     */
    public class DijkstraAndFloydAlgorithm {
    
        public static final int INFINITE = 1000;
    
        public static void main(String[] args) {
            int[][] distance = new int[][] { { 0, 10, INFINITE, 30, 100 }, { INFINITE, 0, 50, INFINITE, INFINITE },
                    { INFINITE, INFINITE, 0, INFINITE, 10 }, { INFINITE, INFINITE, 20, 0, 60 },
                    { INFINITE, INFINITE, INFINITE, INFINITE, 0 } };
            System.out.println("Dijkstra Algorithm:");
            dijkstra(distance, 0);
            System.out.println("Floyd Algorithm:");
            floyd(distance, 1);
        }
    
        // dijkstra algorithm: the source node is giving
        private static void dijkstra(int[][] distance, int source) {
            int nodeSum = distance.length;
            int[] visit = new int[nodeSum];// identify whether the node has been visited
            int[] lowDist = new int[nodeSum];// lowDist[i] = j means min distance of node i to the tree is j
            int[] lowNode = new int[nodeSum];// lowNode[i] = j means node i into the tree via node j
            for (int i = 0; i < nodeSum; i++) {
                lowDist[i] = distance[source][i];
                lowNode[i] = source;
            }
            lowNode[source] = -1;// do this in order to get the path! give it an end
            int minDist, minNode, visitNodeSum = 0, currentNode;//
            visit[source] = 1;
            visitNodeSum++;
            while (visitNodeSum < nodeSum) {// util all the nodes
                minDist = INFINITE;
                minNode = source;
                for (int i = 0; i < nodeSum; i++) {// get the min Node and Distance
                    if (visit[i] == 0 && lowDist[i] < minDist) {// not visit and dist is less
                        minDist = lowDist[i];
                        minNode = i;
                    }
                }
                if (minNode == source) {// for other nodes,no way can be accessed!
                    break;// node that not print means no way can reach it from the giving source node
                }
                visit[minNode] = 1;
                visitNodeSum++;
                System.out.print("Node= " + minNode + "  Distance= " + minDist + "  Path= " + minNode + " <- ");
                currentNode = minNode;
                while (true) {// print path:in order to get more helpful result
                    if (lowNode[lowNode[currentNode]] != -1) {
                        System.out.print(lowNode[currentNode] + " <- ");
                    } else {
                        System.out.print(lowNode[currentNode]);//
                        break;
                    }
                    currentNode = lowNode[currentNode];
                }
                System.out.println();
                for (int i = 0; i < nodeSum; i++) {// modify the distance
                    if (lowDist[i] > lowDist[minNode] + distance[minNode][i]) {
                        lowDist[i] = lowDist[minNode] + distance[minNode][i];
                        lowNode[i] = minNode;
                    }
                }
            }
        }
    
        // floyd algorithm: get the min distance from the giving source node
        private static void floyd(int[][] distance, int source) {
            int nodeSum = distance.length;
            String[][] path = new String[nodeSum][nodeSum];// get the path
            for (int i = 0; i < nodeSum; i++) {
                for (int j = 0; j < nodeSum; j++) {
                    path[i][j] = distance[i][j] == INFINITE ? "" : " " + i + " ->" + j + " ";
                }
            }
            for (int i = 0; i < nodeSum; i++) {// get min distance between any two nodes
                for (int j = 0; j < nodeSum; j++) {
                    for (int k = 0; k < nodeSum; k++) {
                        if (distance[i][j] > distance[i][k] + distance[k][j]) {
                            distance[i][j] = distance[i][k] + distance[k][j];
                            path[i][j] = path[i][k] + path[k][j];
                        }
                    }
                }
            }
            for (int i = 0; i < nodeSum; i++) {
                if (i == source) {
                    continue;
                }
                System.out.println("Node= " + i + "  Distance= " + distance[source][i] + "  Path= " + path[source][i]);
            }
        }
    }
    
    // result
    // Dijkstra Algorithm:
    // Node= 1 Distance= 10 Path= 1 <- 0
    // Node= 3 Distance= 30 Path= 3 <- 0
    // Node= 2 Distance= 50 Path= 2 <- 3 <- 0
    // Node= 4 Distance= 60 Path= 4 <- 2 <- 3 <- 0
    // Floyd Algorithm:
    // Node= 1 Distance= 10 Path= 0 ->1
    // Node= 2 Distance= 50 Path= 0 ->3 3 ->2
    // Node= 3 Distance= 30 Path= 0 ->3
    // Node= 4 Distance= 60 Path= 0 ->3 3 ->2 2 ->4

    4. AOV网络的拓扑排序

    package graph;
    
    import java.util.ArrayDeque;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    /**
     * AOV网的拓扑排序
     * 
     * @author yinger
     */
    public class AOVNetwork {
    
        public static void main(String[] args) {
            int nodeSum = 6;
            AovEdge edge1 = new AovEdge(1, 0);
            AovEdge edge2 = new AovEdge(1, 3);
            AovEdge edge3 = new AovEdge(2, 0);
            AovEdge edge4 = new AovEdge(2, 3);
            AovEdge edge5 = new AovEdge(3, 0);
            AovEdge edge6 = new AovEdge(3, 5);
            AovEdge edge7 = new AovEdge(4, 2);
            AovEdge edge8 = new AovEdge(4, 3);
            AovEdge edge9 = new AovEdge(4, 5);
            List<AovEdge> edgeList = new ArrayList<AovEdge>();
            Collections.addAll(edgeList, edge1, edge2, edge3, edge4, edge5, edge6, edge7, edge8, edge9);
    
            AovNode[] linkTable = new AovNode[nodeSum];
            for (int i = 0; i < nodeSum; i++) {// init linkTable
                linkTable[i] = new AovNode(i);
            }
            buildLinkTable(linkTable, edgeList);
            topsort(linkTable);
        }
    
        // get graph adjust link table according the edge list
        private static void buildLinkTable(AovNode[] linkTable, List<AovEdge> edgeList) {
            AovEdge edge;
            for (int i = 0; i < edgeList.size(); i++) {
                edge = edgeList.get(i);
                linkTable[edge.start].linkNodes.add(linkTable[edge.end]);
                linkTable[edge.end].inDegree++;// in degree!
            }
            // for (int i = 0; i < linkTable.length; i++) {//test linktable
            // System.out.print("Node= " + i + "  LinkNodes= ");
            // for (int j = 0; j < linkTable[i].linkNodes.size(); j++) {
            // System.out.print(linkTable[i].linkNodes.get(j).id+"  ");
            // }
            // System.out.println();
            // }
        }
    
        private static void topsort(AovNode[] linkTable) {
            int nodeSum = linkTable.length;
            int[] visit = new int[nodeSum];// visit = 0:not in stack,not visit;=1: visited;=2:in stack,not visit
            ArrayDeque<AovNode> deque = new ArrayDeque<AovNode>();
            for (int i = 0; i < nodeSum; i++) {
                if (visit[i] == 0 && linkTable[i].inDegree == 0) {// node with in degree = 0 should be in deque
                    deque.addLast(linkTable[i]);
                    visit[i] = 2;// in stack,but not visit!
                }
            }
    //        System.out.println();//test deque
    //        System.out.print("Deque: ");
    //        for (AovNode aovNode : deque) {// test deque
    //            System.out.print(aovNode.id + "  ");
    //        }
    //        System.out.println();
            AovNode node, linkNode;
            while ((node = deque.pollLast()) != null) {
                visit[node.id] = 1;// visit the node
                System.out.print(node.id + " - ");
                for (int i = 0; i < node.linkNodes.size(); i++) {
                    linkNode = node.linkNodes.get(i);
                    if (visit[linkNode.id] != 1) {// visited node not concern
                        linkTable[linkNode.id].inDegree--;
                    }
                }
                for (int i = 0; i < nodeSum; i++) {
                    if (visit[i] == 0 && linkTable[i].inDegree == 0) {// node with in degree = 0 should be in deque
                        deque.addLast(linkTable[i]);
                        visit[i] = 2;// in stack,but not visit!
                    }
                }
            }
        }
    
    }
    
    class AovEdge {
    
        int start;
        int end;
    
        public AovEdge(int start, int end) {
            this.start = start;
            this.end = end;
        }
    
    }
    
    class AovNode {
    
        int id;
        int inDegree;// in degree of the node
        List<AovNode> linkNodes = new ArrayList<AovNode>();
    
        public AovNode(int id) {
            this.id = id;
        }
    
    }

    谢谢阅读,如果发现错误,请及时回复我!

  • 相关阅读:
    【NOI D2T1】量子通信(容斥原理+卡常)
    CF1555D Say No to Palindromes(线段树)
    CF1554B Cobb
    CF1554A Cherry
    【做题笔记】UVA10162 Last Digit
    【做题记录】CF1223D Sequence Sorting
    CF39H
    UVA10763
    题解 AT2361 [AGC012A] AtCoder Group Contest
    このブログについて | About this blog
  • 原文地址:https://www.cnblogs.com/yinger/p/2650018.html
Copyright © 2011-2022 走看看