现在的位置: 首页 > 综合 > 正文

【原创】Java与数据结构(下篇:图)

2012年10月13日 ⁄ 综合 ⁄ 共 13046字 ⁄ 字号 评论关闭

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

}

 

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

 

抱歉!评论已关闭.