图的深度优先遍历和广度优先遍历

news/2024/7/20 20:25:12 标签: 深度优先, 宽度优先, 算法

目录

图的创建和常用方法

深度优先遍历(Depth First Search)

广度优先遍历(Broad First Search) 


图的创建和常用方法

//无向图
public class Graph {
    //顶点集合
    private ArrayList<String> vertexList;
    //存储对应的邻接矩阵
    private int[][] edges;
    //边数
    private int numOfEdges;

    //构造方法
    //传入顶点数
    public Graph(int numOfVertex) {
        this.vertexList = new ArrayList<>(numOfVertex);
        this.edges = new int[numOfVertex][numOfVertex];
        this.numOfEdges = 0;//边数初始为0
    }
    //添加顶点
    public void  interVertex(String vertex){
        vertexList.add(vertex);
    }
    //添加边
    public void interEdge(int v1,int v2,int weight){
        edges[v1][v2] = weight;
        edges[v2][v1] = weight;
        numOfEdges++;
    }


//图中常用方法:
    //返回节点的个数
    public int getNumOfVertex(){
        return vertexList.size();
    }
    //得到边的数目
    public int getNumOfEdges(){
        return numOfEdges;
    }
    //返回节点i对应的数据,以添加的顺序为准
    public String getValueByIndex(int i){
        return vertexList.get(i);
    }
    //返回v1,v2的权值
    public int getWeight(int v1,int v2){
        return edges[v1][v2];
    }
    //显示图所对应的矩阵
    public void showGraph(){
        for(int[] link:edges){
            System.out.println(Arrays.toString(link));
        }
    }

    //测试
    public static void main(String[] args) {
        int n = 5;
        String[] vertexs={"A","B","C","D","E"};
        Graph graph = new Graph(n);
        //添加顶点
        for(String vertex:vertexs){
            graph.interVertex(vertex);
        }
        //添加边:A-C  A-B  A-E  B-D
        graph.interEdge(0,2,1);
        graph.interEdge(0,1,1);
        graph.interEdge(0,4,1);
        graph.interEdge(1,3,1);

        graph.showGraph();
    }
}

邻接矩阵: 

 

 

 

深度优先遍历(Depth First Search)

深度优先:每次访问当前节点后,首先访问当前节点的第一个邻接矩阵

添加标记顶点是否访问的数组:

 private boolean[] isVisted;

 在构造方法中初始化:

  this.isVisted = new boolean[numOfVertex];

得到第一个邻接节点的下标w: 

 //得到第一个邻接节点的下标w
    public int getFirstNeighbor(int index){
        for (int j = 0; j< vertexList.size(); j++) {
            if (edges[index][j]>0){
                return j;
            }
        }
        return -1;
    }

 根据前一个节点的坐标获取下一个邻接节点:

//根据前一个节点的坐标获取下一个邻接节点
    public int getNextNeighbor(int v1,int v2){
        for (int j = v2+1; j < vertexList.size(); j++) {
            if (edges[v1][j]>0)return j;
        }
        return -1;
    }

深度优先遍历: 

 //深度优先遍历
    private void dfs(boolean[] isVisted,int i){
        //首先访该节点,输出
        System.out.print(getValueByIndex(i)+"->");
        //访问标记
        isVisted[i] = true;
        //访问节点的第一个邻接节点
        int w = getFirstNeighbor(i);
        while (w!=-1){
            //有的话并且没有被访问过,就遍历该节点
            if (!isVisted[w]){
                dfs(isVisted,w);
            }
            //如果已经被访问过,就访问下一个
            w = getNextNeighbor(i,w);
        }
    }

 若是非连通图(有孤立点),需要将每个顶点深度遍历:

//若是非连通图,需要将每个顶点深度遍历
    public void dfs(){
        for (int i = 0; i < vertexList.size(); i++) {
            if (!isVisted[i]){
                dfs(isVisted,i);
            }
        }
    }

 如下图的深度遍历:

 

 //测试
    public static void main(String[] args) {
        int n = 6;
        String[] vertexs={"A","B","C","D","E","F"};
        Graph graph = new Graph(n);
        //添加顶点
        for(String vertex:vertexs){
            graph.interVertex(vertex);
        }
        //添加边:A-C  A-B  A-E  B-D
        graph.interEdge(0,2,1);
        graph.interEdge(0,1,1);
        graph.interEdge(0,4,1);
        graph.interEdge(1,3,1);

        graph.showGraph();

        graph.dfs();
    }

广度优先遍历(Broad First Search) 

 广度优先:先访问所有直接相邻的节点,然后访问所有与这些节点相邻的节点,以此类推,直到遍历完整个图。

//广度优先遍历
    //对一个节点进行广度优先算法
    private void bfs(boolean[] isVisted,int i){
        int u;//队列头结点的下标
        int w;//邻接节点
        LinkedList queue = new LinkedList();
    //  访问节点,输出
        System.out.print (getValueByIndex(i)+"=>");
    //    标记已访问
        isVisted[i]=true;
    //    添加到队列
        queue.addLast(i);
        while (!queue.isEmpty()){
            u = (Integer) queue.removeFirst();
            //得到第一个邻接节点的下标
            w = getFirstNeighbor(u);
            while (w!=-1){
                if (!isVisted[w]){
                    //没有访问过
                    System.out.print(getValueByIndex(w)+"=>");
                    isVisted[w] = true;
                    queue.addLast(w);
                }
                //以u为前一个节点,访问过去下一个节点
                w = getNextNeighbor(u, w);
            }
        }

    }
    //非连通图 广度优先遍历
    public void bfs(){
        this.isVisted = new boolean[vertexList.size()];
        for (int i = 0; i < vertexList.size(); i++) {
            if (!isVisted[i]){
                bfs(isVisted,i);
            }
        }
    }

测试:

System.out.println("广度优先");
graph.bfs();

 深度和广度测试:

public static void main(String[] args) {
        int n = 8;
        String[] vertexs={"1","2","3","4","5","6","7","8"};
        Graph graph = new Graph(n);
        //添加顶点
        for(String vertex:vertexs){
            graph.interVertex(vertex);
        }
        //添加边:1-2 1-3 2-4 2-5 4-8 5-8 3-6 3-7
        graph.interEdge(0,1,1);
        graph.interEdge(0,2,1);
        graph.interEdge(1,3,1);
        graph.interEdge(1,4,1);
        graph.interEdge(3,7,1);
        graph.interEdge(4,7,1);
        graph.interEdge(2,5,1);
        graph.interEdge(2,6,1);

        graph.showGraph();
        System.out.println("深度优先");
        graph.dfs();
        System.out.println();
        System.out.println("广度优先");
        graph.bfs();
    }

 

 


http://www.niftyadmin.cn/n/4927585.html

相关文章

Opencv项目实战:24 石头剪刀布

目录 0、项目介绍 1、效果展示 2、项目搭建 3、项目代码展示与部分讲解 pyzjr库

整理mongodb文档:改

个人博客 整理mongodb文档:改 求关注&#xff0c;求批评&#xff0c;求进步 文章概叙 本文主要讲的是mongodb的updateOne以及updateMany&#xff0c;主要还是在shell下进行操作&#xff0c;也讲解下主要的参数upsert以及更新的参数。 数据准备 本次需要准备的数据不是很多…

uniapp文件下载并预览

大概就是这样的咯&#xff0c;文件展示到页面上&#xff0c;点击文件下载并预览该文件&#xff1b; 通过点击事件handleDownLoad(file.path)&#xff0c;file.path为文件的地址&#xff1b; <view class"files"><view class"cont" v-for"(…

3.5 C++ 纯虚函数、抽象类 3.6 依赖倒转原则

纯虚函数 class A { public:virtual void print(){cout<<"A"<<endl;}virtual void test()0; //纯虚函数 }; 一个类内有纯虚函数&#xff0c;这个类就叫抽象类&#xff1b; 抽象类不能实例化&#xff1b; <java、python&#xff1a…

流量分析日志查看

一流量分析 buuctf wireshark 从题目出发&#xff0c;既然是上传登录信息&#xff0c;就直接过滤post请求&#xff0c;即搜索 http.request.methodPOST&#xff0c;因为上传用户登录信息使用的一定是http里的post方法 模式过滤 http.request.method “GET” http.request.…

如何通过nginx反向代理实现不同域名映射到同一台服务器的相同端口

要在Nginx中实现不同域名映射到同一台服务器的相同端口&#xff0c;您可以使用Nginx的代理转发技术。 首先&#xff0c;您需要了解Nginx的代理转发工作原理。Nginx的代理转发是指在代理服务器&#xff08;proxy server&#xff09;收到一个请求时&#xff0c;先将请求转发给目…

[C++]02.选择结构与循环结构

02.选择结构与循环结构 一.程序流程结构1.选择结构1.1.if语句1.2.三目运算符1.3.switch语句 2.循环结构2.1.while语句2.2.do-while语句2.3.for语句2.4.break语句2.5.continue语句2.6.goto语句 一.程序流程结构 C/C支持的最基本的运行结构: 顺序结构, 选择结构, 循环结构顺序结…

1030:计算球的体积

【题目描述】 对于半径为r的球&#xff0c;其体积的计算公式为V4/3π(r^3)&#xff0c;这里取π3.14。现给定r&#xff0c;即球半径&#xff0c;类型为double&#xff0c;求球的体积V&#xff0c;保留到小数点后2位。 【输入】 输入为一个不超过100的非负实数&#xff0c;即…