zoukankan      html  css  js  c++  java
  • 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. 有时间再修改完善
  • 相关阅读:
    iOS中的导航条UINavigationController(UISegmentedControl)的基本使用(界面中传值的3中方法,单例,属性,代理)
    iOS中的分页控件(UIPageControl)
    iOS中的UIScorllView(滑动控件,时机控制)的基本使用
    iOS中ScrollView(滚屏,引导界面,和判段是否是第一次登陆)
    iOS中自定义UIView(用接口获取Lable和TextFile中的值)
    iOS中的手势识别的积累:UIGestureRecognizer(轻拍手势,长按手势,清扫手势,平移手势,捏合手势,旋转手势,屏幕边缘平移手势) ----仿射变换
    iOS中纯手工图片浏览器
    IOS中的TOM(解决缓存,图片加载)
    iOS中的NSString引用计数问题(-1和整数最大值)
    iOS中的内存管理精讲
  • 原文地址:https://www.cnblogs.com/treasury/p/12781533.html
Copyright © 2011-2022 走看看