数据结构与算法(Java)之图

深度优先与广度优先

package com.weeks.graph;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;

/**
 * @author 达少
 * @version 1.0
 *
 * 无向图
 *
 */
public class Graph {

    private ArrayList<String> vertexList;//用于存储图的顶点
    private int[][] edges;//用处存储顶点与顶点的联系(边)
    private int edgesNumber;//记录边的数量
    private boolean[] isVisited;//记录对应的顶点有没有被访问过


    public static void main(String[] args) {
        //创建图对象
        Graph graph = new Graph(5);
        //插入顶点
        graph.insertVertex("A");
        graph.insertVertex("B");
        graph.insertVertex("C");
        graph.insertVertex("D");
        graph.insertVertex("E");

        //插入边A-B,A-C,B-C,B-E,B-D
        graph.inertEdge(0, 1, 1);
        graph.inertEdge(0, 2, 1);
        graph.inertEdge(1, 2, 1);
        graph.inertEdge(1, 3, 1);
        graph.inertEdge(1, 4, 1);

        //显示图
        graph.showGraph();

        //测试深度优先遍历
//        graph.dfs();
        //测试广度优先遍历
        graph.bfs();
    }

    /**
     * 初始化图
     * @param n 表示改图有多少个顶点
     *
     */
    public Graph(int n){
        this.vertexList = new ArrayList<String>(n);
        this.edges = new int[n][n];
        this.edgesNumber = 0;//初始化为零
        this.isVisited = new boolean[n];//大小就是顶点的数量
    }

    //插入顶点
    public void insertVertex(String vertex){
        vertexList.add(vertex);
    }

    //插入边

    /**
     *
     * @param v1 表示边连接的一端的顶点的下标
     * @param v2 表示边连接的另一端的顶点的下标
     * @param weight 表示这条边的权值,我们定义的无向图,两个顶点之间有直接关联的权值为1,否则为0
     */
    public void inertEdge(int v1, int v2, int weight){
        edges[v1][v2] = 1;
        edges[v2][v1] = 1;
        edgesNumber++;//边的个数加1
    }

    //获取图顶点的个数
    public int getVertexNumber(){
        return vertexList.size();
    }

    //获取边的个数
    public int getEdgesNumber(){
        return edgesNumber;
    }

    //显示图,就是遍历二维数组
    public void showGraph(){
        for (int[] line : edges){
            System.out.println(Arrays.toString(line));
        }
    }

    //获取对应的顶点值
    public String getValueByIndex(int index){
        if(index < vertexList.size()){
            return vertexList.get(index);
        }
        return null;
    }

    //获取一个顶点的第一个邻接顶点
    public int getFirstNeighbor(int index){
        //遍历二维数组edges的第index行(index代表第几个顶点)
        for (int i = 0; i < vertexList.size(); i++) {
            //当edges[index][i]不为0则说明index顶点与i顶点连接的
            if(edges[index][i] > 0){//说明找到了,放回顶点下标
                return i;
            }
        }
        //找不到就返回-1
        return -1;
    }

    //获取一个顶点的第一个邻接顶点的下一个临界点
    /**
     *
     * @param v1 当前顶点
     * @param v2 当前顶点的第一个邻接顶点
     * @return 如果存在v1的第一个邻接点的下一个结点
     */
    public int getNextNeighbor(int v1, int v2){
        for(int i = v2 + 1; i < vertexList.size(); i++){
            if(edges[v1][i] > 0){
                return i;
            }
        }
        return -1;
    }

    //深度优先遍历图
    private void dfs(boolean[] isVisited, int index){
        //首先访问当前顶点
        System.out.print(getValueByIndex(index) + "->");
        //将当前顶点设置为已被访问过
        isVisited[index] = true;
        //当前顶点的第一个邻接顶点
        int w = getFirstNeighbor(index);
        while(w != -1){//说明存在下一个邻接点
            //如果w没有被访问过,就继续递归
            if(!isVisited[w]){
                dfs(isVisited, w);
            }
            //如果被访问过,则需要找到当前顶点的下一个顶点
            w = getNextNeighbor(index, w);
        }
    }
    //上面的dfs的逻辑只是完成了对一个顶点的操作,接下来就是循环遍历顶点列表
    //对每个顶点进行同样的操作
    public void dfs(){
        for(int i = 0; i < getVertexNumber(); i++){
            if(!isVisited[i]) {
                dfs(this.isVisited, i);
            }
        }
    }

    //广度优先遍历
    private void bfs(boolean[] isVisited, int index){
        //队列,记录访问顶点的顺序
        LinkedList queue = new LinkedList();
        //记录当前队列的头部元素对应的顶点下标
        int u;
        //记录当前顶点的第一个邻接点的下标
        int w;
        //访问当前顶点
        System.out.print(getValueByIndex(index) + "=>");
        //将当前顶点设置为以访问
        isVisited[index] = true;
        //将当前点加入访问列表中
        queue.addLast(index);
        //当队列不为空,取出队列中的顶点
        while(!queue.isEmpty()){
            //取出头节点的下标
            u = (Integer) queue.removeFirst();
            //得到第一个邻接点的下标
            w = getFirstNeighbor(u);
            if(w != -1){//证明找到邻接点
                //判断是否被访问过
                if(!isVisited[w]){//没有被访问
                    //那么就访问w这个顶点
                    System.out.print(getValueByIndex(w) + "=>");
                    //并将w顶点设置为被访问
                    isVisited[w] = true;
                    //并将w顶点加入访问列表中
                    queue.addLast(w);
                }
                //如果被访问过那么将继续查找u顶点的下一个邻接顶点
                w = getNextNeighbor(u, w);//体现了广度优先
            }
        }
    }
    //上面的bfs的逻辑只是完成了对一个顶点的操作,接下来就是循环遍历顶点列表
    //对每个顶点进行同样的操作
    public void bfs(){
        for(int i = 0; i < getVertexNumber(); i++){
            if(!isVisited[i]){
                bfs(this.isVisited, i);
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数据结构与算法Java编程中扮演着非常重要的角色。数据结构是指在计算机中存储和组织数据的方式,而算法则是指解决问题的步骤和策略。了解和掌握数据结构算法对于编写高效且可维护的Java程序至关重要。 在Java中,有许多常见的数据结构算法可以使用。比如数组、栈、队列、链表、树等。这些数据结构可以帮助我们在处理不同类型的数据时更加高效地存储和访问数据。同时,各种排序算法如冒泡排序、选择排序、插入排序、归并排序、快速排序等也是在Java编程中经常使用的算法。 通过学习和应用数据结构算法,我们可以提高程序的执行效率和性能。在面试中,数据结构算法的知识也是经常被考察的内容。因此,掌握Java中的数据结构算法对于提升编程能力和面试竞争力都非常重要。 引用提供了一些常用数据结构的介绍,包括数组、栈、队列、链表、树和图等。而引用则提供了一些常见的排序算法的介绍,如冒泡排序、选择排序、插入排序、归并排序、快速排序等。通过学习和实践这些数据结构算法,可以帮助我们更好地理解和应用于Java编程中。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [数据结构与算法详解(含算法分析、动图图解、Java代码实现、注释解析)](https://blog.csdn.net/yuan2019035055/article/details/120262225)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值