java实现自定义图

图的表示

图的表示方法有俩种,邻接矩阵和邻接表。俩种方法各有特色。

邻接矩阵:边的关系使用二维数组保存。邻接表:边的关系使用链表

本文以邻接矩阵来演示图的基本操作。

图顶点类

  • isVisited代表该节点是否访问过
public class Vertex {
    //显示A,B,C,D
    public char label;
    public boolean isVisited=false;
    public Vertex(char lable){
        this.label=lable;
    }
}

图类

  • 成员变量需要有保存顶点的数组

  • 保存边的二维数组

  • 顶点的最大数目

  • 当前顶点数

  • 栈和队列是dfs和bfs使用的,我调用的是我自己写的api

初始化

 public Graph(){
        verticesList=new Vertex[maxSize];
        adjMat=new int[maxSize][maxSize];
        //初始化邻接矩阵,为0代表没有链接
        for (int i = 0; i < maxSize; i++) {
            for (int j = 0; j < maxSize; j++) {
                adjMat[i][j]=0;
            }
        }
        nVertext=0;
        stack=new MyStack(maxSize);
        queue=new MyQueue(maxSize);
    }

深度优先搜索

public void dfs(){
        //首先访问0号顶点
        verticesList[0].isVisited=true;
        //显示该顶点
        displayVertex(0);
        //压入栈
        stack.push(0);
        while (!stack.empty()){
            int v=getUnvisitedVertex(stack.peek());
            if(v==-1){
                //找不到
                stack.pop();
            } else {
                verticesList[v].isVisited=true;
                displayVertex(v);
                stack.push(v);
            }
        }
        //搜索完成以后复原
        for (int i = 0; i < nVertext; i++) {
            verticesList[i].isVisited=false;
        }

    }

广度优先搜索

public void bfs(){
        //首先访问0号顶点
        verticesList[0].isVisited=true;
        //显示该顶点
        displayVertex(0);
        //添加到队列
        queue.insert(0);
        while (!queue.empty()){
            int v=getUnvisitedVertex(queue.peek());
            //添加未被访问的节点
            while (v!=-1){
                verticesList[v].isVisited=true;
                displayVertex(v);
                queue.insert(v);
                v=getUnvisitedVertex(queue.peek());
            }
            queue.remove();
        }
        //搜索完成以后复原
        for (int i = 0; i < nVertext; i++) {
            verticesList[i].isVisited=false;
        }

    }

图的最小生成树

最小生成树就是走最少的路线遍历完整个图,实现和dfs几乎一模一样

我只是做了简单的修改,打印出最小生成树路径

public void mst(){
        //首先访问0号顶点
        verticesList[0].isVisited=true;

        //压入栈
        stack.push(0);
        while (!stack.empty()){
            int cur=stack.peek();

            int v=getUnvisitedVertex(stack.peek());
            if(v==-1){
                //找不到
                stack.pop();
            } else {
                verticesList[v].isVisited=true;
                stack.push(v);
                //打印路径
                displayVertex(cur);
                System.out.print("-");
                displayVertex(v);
                System.out.print(" ");

            }
        }
        //搜索完成以后复原
        for (int i = 0; i < nVertext; i++) {
            verticesList[i].isVisited=false;
        }

    }

总体实现

public class Graph {

    //顶点数组
    private Vertex[] verticesList;
    //邻接矩阵adjacent matrix
    private int[][] adjMat;
    //顶点的最大数目
    private int maxSize=10;
    //已经添加的顶点
    private int nVertext;

    //栈,dfs
    private MyStack stack;
    //队列
    private MyQueue queue;

    public Graph(){
        verticesList=new Vertex[maxSize];
        adjMat=new int[maxSize][maxSize];
        //初始化邻接矩阵,为0代表没有链接
        for (int i = 0; i < maxSize; i++) {
            for (int j = 0; j < maxSize; j++) {
                adjMat[i][j]=0;
            }
        }
        nVertext=0;
        stack=new MyStack(maxSize);
        queue=new MyQueue(maxSize);
    }
    /**
     * 添加顶点
     */
    public void addVertex(char lable){
        verticesList[nVertext++]=new Vertex(lable);
    }
    /**
     * 添加边
     */
    public void addEdge(int start,int end){
        adjMat[start][end]=1;
        adjMat[end][start]=1;
    }
    /**
     * 获得邻接的未访问过的节点,-1表示找不到
     */
    public int getUnvisitedVertex(int v){
        for(int i=0;i<nVertext;i++){
            if(adjMat[v][i]==1&&verticesList[i].isVisited==false)
                return i;
        }
        return -1;
    }
    public void dfs(){
        //首先访问0号顶点
        verticesList[0].isVisited=true;
        //显示该顶点
        displayVertex(0);
        //压入栈
        stack.push(0);
        while (!stack.empty()){
            int v=getUnvisitedVertex(stack.peek());
            if(v==-1){
                //找不到
                stack.pop();
            } else {
                verticesList[v].isVisited=true;
                displayVertex(v);
                stack.push(v);
            }
        }
        //搜索完成以后复原
        for (int i = 0; i < nVertext; i++) {
            verticesList[i].isVisited=false;
        }

    }
    public void bfs(){
        //首先访问0号顶点
        verticesList[0].isVisited=true;
        //显示该顶点
        displayVertex(0);
        //添加到队列
        queue.insert(0);
        while (!queue.empty()){
            int v=getUnvisitedVertex(queue.peek());
            //添加未被访问的节点
            while (v!=-1){
                verticesList[v].isVisited=true;
                displayVertex(v);
                queue.insert(v);
                v=getUnvisitedVertex(queue.peek());
            }
            queue.remove();
        }
        //搜索完成以后复原
        for (int i = 0; i < nVertext; i++) {
            verticesList[i].isVisited=false;
        }

    }
    //最小生成树,链接每个顶点最少的连线,定点数-1
    public void mst(){
        //首先访问0号顶点
        verticesList[0].isVisited=true;

        //压入栈
        stack.push(0);
        while (!stack.empty()){
            int cur=stack.peek();

            int v=getUnvisitedVertex(stack.peek());
            if(v==-1){
                //找不到
                stack.pop();
            } else {
                verticesList[v].isVisited=true;
                stack.push(v);
                //打印路径
                displayVertex(cur);
                System.out.print("-");
                displayVertex(v);
                System.out.print(" ");

            }
        }
        //搜索完成以后复原
        for (int i = 0; i < nVertext; i++) {
            verticesList[i].isVisited=false;
        }

    }

    public void displayVertex(int v){
        System.out.print(verticesList[v].label+"");
    }
}

测试类

结点构成了互相连接的五角星,测试dfs,bfs和图的最小生成树

public class GraphTest {
    public static void main(String[] args) {
        Graph graph=new Graph();
        graph.addVertex('A');
        graph.addVertex('B');
        graph.addVertex('C');
        graph.addVertex('D');
        graph.addVertex('E');
        graph.addEdge(0,1);
        graph.addEdge(0,2);
        graph.addEdge(0,3);
        graph.addEdge(0,4);
        graph.addEdge(1,2);
        graph.addEdge(1,3);
        graph.addEdge(1,4);
        graph.addEdge(2,3);
        graph.addEdge(2,4);
        graph.addEdge(3,4);


        graph.dfs();
        System.out.println();
        graph.bfs();
        System.out.println();
        graph.mst();
    }
}

1587896003849

总结

  1. 图的顶点最重要的是要有一个访问属性
  2. 图的主要操作是增加节点,增加边,遍历,求最小生成树

反思

  1. 从测试中就看出代码写的比较繁琐,预想中构造一个图直接传入边就好了,比如 new Graph('A','B')
  2. 节点类型可以拓展成泛型
  3. dfs和bfs可以使用递归实现,比较懒就不写了
  4. 有时间再修改完善
原文地址:https://www.cnblogs.com/treasury/p/12781533.html