数据结构-06 图

创建临界矩阵来表示图

    //表示不相连
    int MAX_WEIGHT = 1000;

    //构建用来表示图的邻接矩阵
      int[][] matrix = 
    {{0,10,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,11,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT},
    {10,0,18,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,16,MAX_WEIGHT,12},
    {MAX_WEIGHT,MAX_WEIGHT,0,22,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,8},
    {MAX_WEIGHT,MAX_WEIGHT,22,0,20,MAX_WEIGHT,MAX_WEIGHT,16,21},
    {MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,20,0,26,MAX_WEIGHT,7,MAX_WEIGHT},
    {11,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,26,0,17,MAX_WEIGHT,MAX_WEIGHT},
    {MAX_WEIGHT,16,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,17,0,19,MAX_WEIGHT},
    {MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,16,7,MAX_WEIGHT,19,0,MAX_WEIGHT},
    {MAX_WEIGHT,12,8,21,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,0}};

    //顶点的个数
    int verticalSize = matrix.length; 

    //用来表示已经遍历的顶点
    boolean [] isVisited;

获取某个顶点的第一个临界点

private int getFirstNeighbor(int index){
        for(int i=0;i<verticalSize;i++ ){
            if(matrix[index][i]>0&&matrix[index][i]<MAX_WEIGHT){
                return i;
            }
        }
        return -1;
    }

根据某个顶点的临界点 获取相对于这个临界点的下一个临界点

private int getNextNeighbor(int index){
        for(int i=index;i<verticalSize;i++){
            if(matrix[index][i]>0&&matrix[index][i]<MAX_WEIGHT){
                return i;
            }
        }
        return -1;
    }

1 图的深度优先遍历

  • 把图看成一个树结构
  • 其遍历方法类似树的遍历

这里写图片描述

/**
     * 对外公开的深度优先遍历
     * @param index
     */
    public void depFirstSearch(int index){
        isVisited = new boolean[verticalSize];

        //如果某个顶点和其他没有交点
        for(int i=0;i<verticalSize;i++){
            if(!isVisited[i]){
                System.out.println("遍历到第"+i+"个顶点");
                isVisited[i] = true;
                depthFirstSearch(i);
            }
        }
    }

    /**
     * 深度优先遍历
     * @param index
     */
    private void depthFirstSearch(int index){
        int w = getFirstNeighbor(index);
        while(w!=-1){
            if(!isVisited[w]){
                isVisited[w] = true;
                System.out.println("遍历到第"+w+"个顶点");
                depthFirstSearch(w);
            }
            w = getNextNeighbor(index,w);
        }
    }

2 图的广度优先遍历

  • 用一个queue来表示未遍历的顶点
  • 外层循环遍历queue中的顶点
  • 内层循环遍历queue中每个顶点的下一个顶点
    这里写图片描述
public void broadfirstSearch(int index){
        isVisited = new boolean [verticalSize];
        for(int i=0;i<verticalSize;i++){
            if(!isVisited[i]){
                broadFirstSearch(i);
            }
        }
    }

    /**
     * 广度优先遍历
     * @param index
     */
    private void broadFirstSearch(int index){
        int u,w;
        System.out.println("遍历到第"+index+"个顶点");
        isVisited[index] = true;
        LinkedList<Integer> queue = new LinkedList();
        queue.add(index);
        //遍历queue中的每个顶点
        while(!queue.isEmpty()){
            u = (Integer)queue.removeFirst().intValue();
            w = getFirstNeighbor(u);
            //遍历queue中的每个顶点对应的下一个顶点
            while(w!=-1){
                if(!isVisited[w]){
                    System.out.println("遍历到第"+w+"个顶点");
                    isVisited[w] = true;
                    queue.add(w);
                }
                w = getNextNeighbor(u,w);
            }
        }

    }

3 普里姆算法 找到图的最小生成树

  • 每次从已经找到的邻接点中找到下个最小的路径作为最小生成树的下一个顶点

右边的数组表示lowCost

这里写图片描述

    /**
     * 普里姆算法    找到图的最小生成树
     */
    private void prim(){
        int [] lowCost = new int [verticalSize];//最小代价顶点的数组,为0说明已经找到
        int [] adjex = new int[verticalSize]; //放顶点的权值
        int min,midId,sum = 0;

        //初始化lowCost
        for(int i =1;i<verticalSize;i++){
            lowCost[i] = matrix[0][i];
        }

        //每次找到一条最短路径 路径的条数比结点数小1 所以遍历的次数比结点数小1
        for(int i=1;i<verticalSize;i++){
            min = MAX_WEIGHT;
            midId = 0;

            //每次从lowCost中找到一个最小值 作为最小生成树的其中一条最短路径
            //从1开始遍历是因为不用再考虑V0
            for(int j =1;j<verticalSize;j++){
                if(lowCost[j]<min&&lowCost[j]>0){
                    min = lowCost[j];
                    midId = j;
                }
            }

            System.out.println("顶点:"+adjex[midId]+"权值:"+min);
            sum+=min;
            lowCost[midId] = 0;
            //根据找到的最短路径,找到对应的结点。此结点的所有临界点的最小值替换为lowCost中的值
            for(int j=1;j<verticalSize;j++){
                if(lowCost[j]!=0&&matrix[midId][j]<lowCost[j]){
                    lowCost[j] = matrix[midId][j];
                    adjex[j] = midId;
                }
            }

        }

        System.out.println("最小生成树的权值和:"+sum);
    }

4 克鲁斯卡尔算法 找到图的最小生成树

  • 构建一个用边表示的数组,数组中边的长度按照从小到大排列。
  • 如果连接后不能形成回环,就连接,否则不连

这里写图片描述

构建边的数组

    /**
     * 构建一个边的数组
     */
    public void createEdgeArray(){
        Edge adge0 = new Edge(4, 7, 7);
        Edge adge1 = new Edge(2, 8, 8);
        Edge adge2 = new Edge(0, 1, 10);
        Edge adge3 = new Edge(0, 5, 11);
        Edge adge4 = new Edge(1, 8, 12);
        Edge adge5 = new Edge(3, 7, 16);
        Edge adge6 = new Edge(1, 6, 16);
        Edge adge7 = new Edge(5, 6, 17);
        Edge adge8 = new Edge(1, 2, 18);
        Edge adge9 = new Edge(6, 7, 19);
        Edge adge10 = new Edge(3, 4, 20);
        Edge adge11= new Edge(3, 8, 21);
        Edge adge12 = new Edge(2, 3, 22);
        Edge adge13= new Edge(3, 6, 24);
        Edge adge14= new Edge(4, 5, 26);

        edges[0] = adge0;
        edges[1] = adge1;
        edges[2] = adge2;
        edges[3] = adge3;
        edges[4] = adge4;
        edges[5] = adge5;
        edges[6] = adge6;
        edges[7] = adge7;
        edges[8] = adge8;
        edges[9] = adge9;
        edges[10] = adge10;
        edges[11] = adge11;
        edges[12] = adge12;
        edges[13] = adge13;
        edges[14] = adge14;
    }
    /**
     * 用来表示边
     */
    class Edge{
        private int begin; //边的起点
        private int end;   //边的终点
        private int weight; //边的权值 即边长
        public Edge(int begin, int end, int weight) {
            super();
            this.begin = begin;
            this.end = end;
            this.weight = weight;
        }
        public int getBegin() {
            return begin;
        }
        public void setBegin(int begin) {
            this.begin = begin;
        }
        public int getEnd() {
            return end;
        }
        public void setEnd(int end) {
            this.end = end;
        }
        public int getWeight() {
            return weight;
        }
        public void setWeight(int weight) {
            this.weight = weight;
        }
    }

克鲁斯卡尔 算法实现

//查询获取非回环的值
    private int find(int[] parent,int f){
        while(parent[f]>0){
            f = parent[f];
        }
        return f;
    }
    /**
     * 克鲁斯卡尔算法 找到最小生成树
     */
    public void miniSpanTreeKruskal(){
        int m,n,sum=0;
        int [] parent = new int[edgSize];//下标为起点 值为终点

        for(int i=0;i<edgSize;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;
            }
        }
        System.out.println("sum="+sum);
    }

5 迪杰斯特拉算法 获取图的最短路径

这里写图片描述

构造图

public class Graph {
    private int vertexSize;//顶点数量

    private int [] vertexs;//顶点数组

    private int[][]  matrix; //用来表示图的邻接矩阵

    private static final int MAX_WEIGHT = 1000;//表示不相连

    private boolean [] isVisited; //是否已经遍历过

    public Graph(int vertextSize){
        this.vertexSize = vertextSize;
        matrix = new int[vertextSize][vertextSize];
        vertexs = new int[vertextSize];
        for(int i = 0;i<vertextSize;i++){
            vertexs[i] = i;
        }
        isVisited = new boolean[vertextSize];
    }

    public int getVertexSize() {
        return vertexSize;
    }
    public void setVertexSize(int vertexSize) {
        this.vertexSize = vertexSize;
    }

    public int[][] getMatrix() {
        return matrix;
    }


    public void setMatrix(int[][] matrix) {
        this.matrix = matrix;
    }

    /**
     * 创建图的过程
     */
    public void createGraph(){
        int [] a1 = new int[]{0,1,5,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT};
        int [] a2 = new int[]{1,0,3,7,5,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT};
        int [] a3 = new int[]{5,3,0,MAX_WEIGHT,1,7,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT};
        int [] a4 = new int[]{MAX_WEIGHT,7,MAX_WEIGHT,0,2,MAX_WEIGHT,3,MAX_WEIGHT,MAX_WEIGHT};
        int [] a5 = new int[]{MAX_WEIGHT,5,1,2,0,3,6,9,MAX_WEIGHT};
        int [] a6 = new int[]{MAX_WEIGHT,MAX_WEIGHT,7,MAX_WEIGHT,3,0,MAX_WEIGHT,5,MAX_WEIGHT};
        int [] a7 = new int[]{MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,3,6,MAX_WEIGHT,0,2,7};
        int [] a8 = new int[]{MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,9,5,2,0,4};
        int [] a9 = new int[]{MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,MAX_WEIGHT,7,4,0};

        matrix[0] = a1;
        matrix[1] = a2;
        matrix[2] = a3;
        matrix[3] = a4;
        matrix[4] = a5;
        matrix[5] = a6;
        matrix[6] = a7;
        matrix[7] = a8;
        matrix[8] = a9;
    }
}

迪杰斯特拉算法实现

    private final static int MAXVEX = 9;
    private final static int MAXWEIGHT = 65535;
    private int shortTablePath[] = new int[MAXVEX];// 记录的是v0到某顶点的最短路径和
public static void main(String[] args){
        Graph graph = new Graph(MAXVEX);
        graph.createGraph();
        Dijstra dijstra = new Dijstra();
        dijstra.shortestPathDijstra(graph);
    }
    /**
     * 获取一个图的最短路径
     */
    public void shortestPathDijstra(Graph graph) {
        int min;
        int k = 0;// 记录下标
        boolean isgetPath[] = new boolean[MAXVEX];
        for (int v = 0; v < graph.getVertexSize(); v++) {
            shortTablePath[v] = graph.getMatrix()[0][v];// 获取v0这一行的权值数组
        }
        shortTablePath[0] = 0;
        isgetPath[0] = true;

        //每次找到shortTablePath中的一个最小值 
        for (int v = 1; v < graph.getVertexSize(); v++) {
            min = MAXWEIGHT;
            //找到shortTablePathh中的最小值并且这个最小值不是最短路径 并记录其下标
            for (int w = 0; w < graph.getVertexSize(); w++) {
                if (!isgetPath[w] && shortTablePath[w] < min) {
                    k = w;
                    min = shortTablePath[w];
                }
            }
            isgetPath[k] = true;
            //根据之前找到的最小值的下标 找到此结点时 shortTable中的最小值 也就是最短路径
            for (int j = 0; j < graph.getVertexSize(); j++) {
                if(!isgetPath[j]&&(min+graph.getMatrix()[k][j]<shortTablePath[j])){
                    shortTablePath[j] = min + graph.getMatrix()[k][j];
                }
            }
        }
        for(int i = 0;i<shortTablePath.length;i++){
            System.out.println("V0到V"+i+"的最短路径为:"+shortTablePath[i]+"\n");
        }

    }

6 拓扑排序

这里写图片描述

public class TopologicSort {

    public static void main(String[] args) {
        TopologicSort sort = new TopologicSort();
        List<VertextNode> nodeList = sort.createGraph();
        sort.topologicSort(nodeList);
    }

    private void topologicSort(List<VertextNode> nodeList){

        //用来存储入度为空的邻接顶点
        Stack<VertextNode> stack = new Stack<VertextNode>();

        //遍历集合中入度为空的邻接顶点 并加入到栈中
        for(int i=0;i<nodeList.size();i++){
            if(nodeList.get(i).in==0){
                stack.push(nodeList.get(i));
            }
        }

        int count=0;

        //当栈中临界点顶个数不为0时,
        while(!stack.isEmpty()){
            VertextNode node = stack.pop();

            count++;
            //遍历每个临界顶点对应的边表顶点 如果边表顶点的下标对应的邻接顶点的入度为0
            for(EdgeNode edgeNode = node.FirstEdge;edgeNode!=null;edgeNode = edgeNode.next){
                int index = edgeNode.vertext;
                if(--nodeList.get(index).in==0){
                    stack.push(nodeList.get(index));
                }
            }

            System.out.println("顶点"+node.getData());
        }

        if(count<nodeList.size()){
            System.out.println("排序失败!");
        }
    }

    private List<VertextNode> createGraph(){
        VertextNode node0 = new VertextNode(0, "V0");
        VertextNode node1 = new VertextNode(0, "V1");
        VertextNode node2 = new VertextNode(2, "V2");
        VertextNode node3 = new VertextNode(0, "V3");
        VertextNode node4 = new VertextNode(2, "V4");
        VertextNode node5 = new VertextNode(3, "V5");
        VertextNode node6 = new VertextNode(1, "V6");
        VertextNode node7 = new VertextNode(2, "V7");
        VertextNode node8 = new VertextNode(2, "V8");
        VertextNode node9 = new VertextNode(1, "V9");
        VertextNode node10 = new VertextNode(1, "V10");
        VertextNode node11 = new VertextNode(2, "V11");
        VertextNode node12 = new VertextNode(1, "V12");
        VertextNode node13 = new VertextNode(2, "V13");

        node0.FirstEdge = new EdgeNode(11);node0.FirstEdge.next = new EdgeNode(5);  node0.FirstEdge.next.next = new EdgeNode(4);
        node1.FirstEdge = new EdgeNode(8);node1.FirstEdge.next = new EdgeNode(4);  node1.FirstEdge.next.next = new EdgeNode(2);
        node2.FirstEdge = new EdgeNode(9);node2.FirstEdge.next = new EdgeNode(6);  node2.FirstEdge.next.next = new EdgeNode(5);
        node3.FirstEdge = new EdgeNode(13);node3.FirstEdge.next = new EdgeNode(2); 
        node4.FirstEdge = new EdgeNode(7);
        node5.FirstEdge = new EdgeNode(12);node5.FirstEdge.next = new EdgeNode(8); 
        node6.FirstEdge = new EdgeNode(5);
        node8.FirstEdge = new EdgeNode(7);
        node9.FirstEdge = new EdgeNode(11);node9.FirstEdge.next = new EdgeNode(10); 
        node10.FirstEdge = new EdgeNode(13);
        node12.FirstEdge = new EdgeNode(9);

        List<VertextNode> nodeList = new ArrayList();
        nodeList.add(node0);
        nodeList.add(node1);
        nodeList.add(node2);
        nodeList.add(node3);
        nodeList.add(node4);
        nodeList.add(node5);
        nodeList.add(node6);
        nodeList.add(node7);
        nodeList.add(node8);
        nodeList.add(node9);
        nodeList.add(node10);
        nodeList.add(node11);
        nodeList.add(node12);
        nodeList.add(node13);


        return nodeList;

    }

    //边表顶点
    class EdgeNode {
        private EdgeNode next;
        private int vertext;

        public EdgeNode(int vertext) {
            super();
            this.vertext = vertext;
        }

        public EdgeNode(EdgeNode next, int vertext) {
            super();
            this.next = next;
            this.vertext = vertext;
        }

    }

    //邻接顶点
    class VertextNode {
        private int in;// 入度个数
        private String data;// V0 V1 V2
        private EdgeNode FirstEdge;

        public VertextNode(int in, String data) {
            super();
            this.in = in;
            this.data = data;
        }

        public int getIn() {
            return in;
        }

        public void setIn(int in) {
            this.in = in;
        }

        public String getData() {
            return data;
        }

        public void setData(String data) {
            this.data = data;
        }

        public EdgeNode getFirstEdge() {
            return FirstEdge;
        }

        public void setFirstEdge(EdgeNode firstEdge) {
            FirstEdge = firstEdge;
        }

    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值