数据结构之图论基础和深度优先与广度优先

本文深入探讨了图论的基础概念,包括无向图、有向图及其变种,阐述了图的度、连通性和权重等关键属性。同时,详细介绍了图的两种表示方法:邻接矩阵和邻接表,并对比了它们的优缺点。此外,还讲解了图的遍历算法——深度优先搜索和广度优先搜索,以及图的相关属性和方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

图论基础

什么是图

在计算机科学中,一个图就是一些顶点的集合,这些顶点通过一系列边结对(连接)。顶点用圆圈表示,边就是这些圆圈之间的连线。顶点之间通过边连接。
在这里插入图片描述
如图 这是一个无向图,其中A、B、C、D、E、F称之为顶点

图的基本概念

图右很多种大概分为 无向图 、有向图。在此基础上还可以添加权重,称之为带权的有向图和无向图。 如果图中的任意两个顶点都是相互连通的则称之为连通图。如下图
在这里插入图片描述
其中图有一个概念就是度,对于无向图 顶点边数叫做度, 对于有向图顶点的边数叫做出度和入度。
如图2 中每个顶点的度都是3
图1中 顶点A的入度是2,出度是0
图3中 顶点A的入度是2,出度是1

图的表达形式

从上面的各种图之间的关系,可以看出顶点与顶点之间相互关系很复杂,计算机领域我们通常两种存储结构表示图,邻接矩阵和邻接表。

邻接矩阵

邻接矩阵使用两个数组来表示图,一个是一维数组用来存储顶点信息,另一个是用一个二维数组表示顶点与顶点之间的关系。

  • 无向图用邻接矩阵表示

在这里插入图片描述

  • 有向图用邻接矩阵表示

在这里插入图片描述

  • 带权有向图邻接矩阵表示
    在这里插入图片描述
邻接表

玲姐表表示图的结构类似于HashMap 的数组+链表的表示方式。这种方式主要为了解决,邻接矩阵占用空间大的问题, 但是其访问方式相比矩阵要复杂并且分析问题难度也较大,所以90%都用矩阵的方式表示图。
在这里插入图片描述
在这里插入图片描述

深度优先与广度优先在这里插入图片描述

深度优先

深度优先遍历也叫做深度优先搜索,它的遍历规则就是不断的沿着顶点的深度方向搜索。如上图的迷宫,每次我们走到一个岔口,按照一定的顺序,发现一个可以走的点,就沿着这个方向一直走,直到无路可走,就返回到上一次的岔口位置换一个方向继续这样走。 这就叫深度优先。
在这里插入图片描述
还是用这个图说明。
从A开始搜索,发现C 可以走。
从C开始,发现B 可以走,
在从B开始,发现A可以走,回到了起点说明不通
退回到C,发现D可以走
从D开始,发现A可以走,由回到起点,说明不通。
上面的就是 深度优先。

/**
 * 深度优先(很象二叉树的前序)
 */
public void dfs() {
    for (int i = 0; i < verticesSize; i++) {
        if (!isVisited[i]) {
            System.out.println("viested vertice " + i);
            dfs(i);
        }
    }
}

public void dfs(int i) {
    isVisited[i] = true;
    //获取到第一个 可以走的点
    int v = getFirstNeightBor(i);
    while (v != -1) {
    	//如果没有被走过
        if (!isVisited[v]) {
            System.out.println("visted vertice " + v);
            // 沿着这个点继续往前走
            dfs(v);
        }
        v = getNextNeightBor(i, v);
    }
}
广度优先

还是上面图的例子,当我们走到一个岔口,我们先遍历这个岔口所有可以走的点 (广度的意思)
还是深度优先的这个图说明。


/**
 * 广度优先
 */
public void bfs(){
    for (int i = 0; i < verticesSize; i++) {
        isVisited[i]=false;
    }
    for (int i = 0; i < verticesSize; i++) {
        if(!isVisited[i]){
            isVisited[i]=true;
            System.out.println("visited vertice:"+ i);
            bfs(i);
        }
    }
}

public void bfs(int i) {
    LinkedList<Integer> queue = new LinkedList<>();
    //找第一个邻接点
    int fn = getFirstNeightBor(i);
    if (fn == -1) {
        return;
    }
    if (!isVisited[fn]) {
        isVisited[fn] = true;
        System.out.println("visted vertice:" + fn);
        queue.offer(fn);
    }
    //开始把后面的邻接点都入队
    int next = getNextNeightBor(i, fn);
    while (next != -1) {
        if (!isVisited[next]) {
            isVisited[next] = true;
            System.out.println("visted vertice:" + next);
            queue.offer(next);
        }
        next = getNextNeightBor(i, next);
    }
    //从队列中取出来一个,重复之前的操作
    while(!queue.isEmpty()){
        int point=queue.poll();//v1  v2
        bfs(point);
    }
}

图相关的属性和方法

public class Graph {
    public int[] vertices;//顶点集
    public int[][] matrix;//图的边的信息
    public int verticesSize;

    public static final int MAX_WEIGHT = Integer.MAX_VALUE;

    public boolean[] isVisited;

    public Graph(int verticesSize) {
        this.verticesSize = verticesSize;
        vertices = new int[verticesSize];
        matrix = new int[verticesSize][verticesSize];
        isVisited = new boolean[verticesSize];
        for (int i = 0; i < verticesSize; i++) {
            vertices[i] = i;
        }
    }
    /**
     * 计算v1到v2的权重(路径长度)
     */
    public int getWeight(int v1, int v2) {
        int weight = matrix[v1][v2];
        return weight == 0 ? 0 : (weight == MAX_WEIGHT ? -1 : weight);
    }

    /**
     * 获取顶点
     */
    public int[] getVertices() {
        return vertices;
    }

    /**
     * 获取出度
     */
    public int getOutDegree(int v) {
        int count = 0;
        for (int i = 0; i < verticesSize; i++) {
            if (matrix[v][i] != 0 && matrix[v][i] != MAX_WEIGHT) {
                count++;
            }
        }
        return count;
    }

    /**
     * 获取入度
     */
    public int getInDegree(int v) {
        int count = 0;
        for (int i = 0; i < verticesSize; i++) {
            if (matrix[i][v] != 0 && matrix[i][v] != MAX_WEIGHT) {
                count++;
            }
        }
        return count;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值