【原创】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; } }
谢谢阅读,如果发现错误,请及时回复我!