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

Posted 达少Rising

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法(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);
            }
        }
    }
}

以上是关于数据结构与算法(Java)之图的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript--数据结构与算法之图

数据结构与算法之图

我的软考之路——数据结构与算法之图

数据结构与算法基础之图的应用-最短路径

数据结构之图:求所有节点之间的最短路径,用啥算法时间复杂度小?求答案与解释

数据结构实验之图论二:图的深度遍历-java代码