• 图的表示方式
      • 邻接矩阵(二维矩阵)
    • 邻接表
    • 图的创建
    • 图的深度优先遍历(DFS)
    • 图的广度优先遍历(BFS)

图是一种数据结构,其节点可以有零个或多个相邻的元素,两个节点相连称为边。

  • 顶点(也就是节点)vertex
  • 边edge
  • 路径
  • 无向图:顶点之间的连接没有方向
  • 有向图:顶点之间的连接有方向
  • 带权图:边上带有权值,也叫网。

图的表示方式

邻接矩阵(二维矩阵)

图_第1张图片邻接矩阵为
图_第2张图片

邻接表

邻接表只关心存在的边,相较于邻接矩阵而言不关心不存在的边,因此没有空间的浪费,邻接表由数组和链表组成。

图_第3张图片邻接表为
图_第4张图片
标号为0的节点相关联节点为1,2,3;。。。。。

图的创建

使用邻接矩阵表示图。
思路:

  1. 使用Arrylist 存储顶点
  2. 使用二维矩阵存储边的信息
    图中常用的方法:返回节点的个数,返回边的数目,返回节点对应的数值,返回边的权值,显示图对应的矩阵
import java.util.ArrayList;
import java.util.Arrays;

public class Graph {
    private ArrayList<String> vertexList;
    private int[][] edge;
    private int edgesNum;
    public static void main(String[] args) {
        String[] vertex = {"A","B","C","D","E"};
        Graph graph = new Graph(vertex.length);
        for(String i:vertex){
            graph.insertVertex(i);
        }
        graph.insertEdge(0,1,1);
        graph.insertEdge(0,2,1);
        graph.insertEdge(1,2,1);
        graph.insertEdge(1,3,1);
        graph.insertEdge(1,4,1);

        graph.getGraph();

    }

    /**
     * 有参构造函数
     * @param n 为图的节点数
     */
    public Graph(int n){
        vertexList = new ArrayList<String>(n);
        edge = new int[n][n];
        edgesNum =0;
    }

    public  void insertVertex(String vertex){
        vertexList.add(vertex);
    }

    public void insertEdge(int v1,int v2,int weight){
        edge[v1][v2]=weight;
        edge[v2][v1]=weight;
        edgesNum++;
    }

    public int getVertexNum(){
        return vertexList.size();
    }

    public int getEdgesNum(){
        return edgesNum;
    }

    /**
     *
     * @param i 节点的索引
     * @return 索引节点的值
     */
    public String getVertex(int i){
        return vertexList.get(i);
    }

    /**
     *
     * @param v1 节点v1的索引
     * @param v2 节点V2的索引
     * @return  两个节点相连边的权值
     */
    public int getWeight(int v1,int v2){
        return edge[v1][v2];
    }
    //打印图的邻接矩阵
    public void getGraph(){
        for(int[] i :edge){
            System.out.println(Arrays.toString(i));
        }
    }
}

图的深度优先遍历(DFS)

深度优先遍历策略是一个往纵向挖掘的过程,其访问节点的过程是:首相访问初始节点,在访问初始节点的一个邻接节点,然后将次节点作为初始节点,再访问它的下一个邻接节点。深度优先遍历是一个递归的过程。

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

public class Graph {
    private ArrayList<String> vertexList;
    private int[][] edge;
    private int edgesNum;
    private boolean[] isVisted;
    //得到第一个邻接节点的下标
public int getFirstneighbour(int i){
    for(int j = 0;j<vertexList.size();j++){
        if(edge[i][j]>0){   //两个节点的边大于0说明相连
            return j;
        }
    }
    return -1; //没有邻接节点
}

/**
 *
 * @param v1 为初始节点
 * @param v2 为初始节点的下一个邻接点但是被访问过了
 * @return  返回一个初始节点没有被访问过的邻接点
 */
public int getNextneighbour(int v1,int v2){
    for(int j=v2+1;j<vertexList.size();j++){
        if(edge[v1][j]>0){
            return j;
        }
    }
    return -1;
}

/**
 *
 * @param isVisted 节点是否访问数组
 * @param i 初始节点
 */
private void dfs(boolean[] isVisted,int i){
    //访问入口的节点
    System.out.print(vertexList.get(i)+"-->");
    isVisted[i] =true;
    int neighbour = getFirstneighbour(i);
    while (neighbour!=-1){  //下一个邻接点存在
        if(isVisted[neighbour]==false){  //下一个邻接点没访问过
            dfs(isVisted,neighbour);
        }else {    //下一个邻接点访问过了
            neighbour = getNextneighbour(i,neighbour);
        }
    }
}

public void dfs(){
    for(int i =0;i<vertexList.size();i++){
        if(isVisted[i]==false){
            dfs(isVisted,i);
        }
    }
}

图的广度优先遍历(BFS)

广度优先遍历类似于分层搜索的过程,需要使用一个队列存储访问的节点。

/**
 * 
 * @param isVisted  节点是否访问数组
 * @param i 初始节点
 */
private void bfs(boolean[] isVisted,int i){
    System.out.print(getVertex(i)+"-->"); //取出初始节点
    isVisted[i] =true; //将初始节点标记为以访问
    Queue<Integer> vertexQueue = new LinkedList<>();
    vertexQueue.add(i);  //将访问的初始节点加入队列
    while (!vertexQueue.isEmpty()) { //队列不为空
        int intial = vertexQueue.poll(); //删除队列头元素
        int neighbour = getFirstneighbour(i); // 获取初始节点的第一个邻接点
        while (neighbour != -1) {  //邻接点存在
            if (isVisted[neighbour] == false) { //邻接点没有访问过
                System.out.print(getVertex(neighbour)+"-->"); //打印邻接点
                isVisted[neighbour] = true; //标记邻接点访问过
                vertexQueue.add(neighbour);//将邻接点加入队列
            } else {
                neighbour = getNextneighbour(intial,neighbour);
            }
        }
    }

}
public void bfs(){
    for(int i=0;i<getVertexNum();i++){
        if(isVisted[i]==false){
            bfs(isVisted,i);
        }
    }
}

图的广度优先遍历思路:

  1. 访问初始节点,将初始节点加入队列中
  2. 判断队列是否为空,不为空:将队列头元素删除,找到初始节点 的第一个邻接节点
  3. 如果第一个邻接节点存在,且没有访问过,则把第一个邻接节点访问,并将其加入队列,
  4. 如果第一个邻接节点存在,且访问过,则找初始节点的第二个邻接节点,再跳转到第3步执行;
  5. 如果队列为空则结束循环,更换初始节点,跳转到1执行。

你可能感兴趣的:(数据结构学习)