一个图G=(V, E)由以下元素组成。

  • V:一组顶点
  • E:一组边,连接V中的顶点


    image.png

相邻顶点

由一条边连接在一起的顶点称为相邻顶点。比如,A和B是相邻的,A和D是相邻的,A和C是相邻的,A和E不是相邻的

一个顶点的度是其相邻顶点的数量。比如,A和其他三个顶点相连接,因此A的度为3; E和其他两个顶点相连,因此E的度为2。

路径

路径是顶点v 1, v2,…, vk的一个连续序列,其中vi和vi+1是相邻的。以上一示意图中的图为例,其中包含路径A B E I和A C D G。

简单路径要求不包含重复的顶点。举个例子,A D G是一条简单路径。除去最后一个顶点(因为它和第一个顶点是同一个顶点),环也是一个简单路径,比如A D C A(最后一个顶点重新回到A)。

如果图中不存在环,则称该图是无环的。如果图中每两个顶点间都存在路径,则该图是连通的。

有向图和无向图

图可以是无向的(边没有方向)或是有向的(有向图)。如下图所示,有向图的边有一个方向。


image.png

如果图中每两个顶点间在双向上都存在路径,则该图是强连通的。例如,C和D是强连通的,而A和B不是强连通的。

图还可以是未加权的(目前为止我们看到的图都是未加权的)或是加权的。如下图所示,加权图的边被赋予了权值。


image.png

入度和出度

在有向图中,我们把度分为入度(In-degree)出度(Out-degree)

顶点的入度,表示有多少条边指向这个顶点;顶点的出度,表示有多少条边是以这个顶点为起点指向其他顶点。

图的表示

1.邻接矩阵

图最常见的实现是邻接矩阵。每个节点都和一个整数相关联,该整数将作为数组的索引。我们用一个二维数组来表示顶点之间的连接。如果索引为i的节点和索引为j的节点相邻,则array[i][j] === 1,否则array[i][j] === 0,如下图所示。

image.png

不是强连通的图(稀疏图)如果用邻接矩阵来表示,则矩阵中将会有很多0,这意味着我们浪费了计算机存储空间来表示根本不存在的边。例如,找给定顶点的相邻顶点,即使该顶点只有一个相邻顶点,我们也不得不迭代一整行。邻接矩阵表示法不够好的另一个理由是,图中顶点的数量可能会改变,而二维数组不太灵活。

2.邻接表

我们也可以使用一种叫作邻接表的动态数据结构来表示图。邻接表由图中每个顶点的相邻顶点列表所组成。存在好几种方式来表示这种数据结构。我们可以用列表(数组)、链表,甚至是散列表或是字典来表示相邻顶点列表。下面的示意图展示了邻接表数据结构。


image.png

尽管邻接表可能对大多数问题来说都是更好的选择,但以上两种表示法都很有用,且它们有着不同的性质(例如,要找出顶点v和w是否相邻,使用邻接矩阵会比较快)

3.关联矩阵

还可以用关联矩阵来表示图。在关联矩阵中,矩阵的行表示顶点,列表示边。如下图所示,使用二维数组来表示两者之间的连通性,如果顶点v是边e的入射点,则array[v][e] === 1;否则,array[v][e] === 0。


image.png

关联矩阵通常用于边的数量比顶点多的情况,以节省空间和内存。

代码demo

    /**
     * 使用邻接表存储图
     * 使用Map表示相邻顶点列表
    */
    class Graph{
      constructor(isDirected = false) {
        // 图是否有向(默认无向)
        this.isDirected = isDirected;
        // 使用数组存储所有顶点
        this.vertices = [];
        // 使用顶点名作为键,相邻顶点作为值
        this.adjList = new Map();
      }
      // 添加顶点
      addVertex(v){
        if(!this.vertices.includes(v)){
          this.vertices.push(v);
          // 顶点v的相邻顶点使用Set存储
          this.adjList.set(v, new Set());
        }
      }
      // 添加边,参数为连接边的两个顶点
      addEdge(v, w){
        if(!this.vertices.includes(v)){
          this.addVertex(v);
        }
        if(!this.vertices.includes(w)){
          this.addVertex(w);
        }
        this.adjList.get(v).add(w);
        // 如果是无向图,则再添加一条w到v的边
        if(!this.isDirected){
          this.adjList.get(w).add(v);
        }
      }
      // 返回顶点列表
      getVertices(){
        return this.vertices;
      }
      // 返回邻接表
      getAdjList(){
        this.adjList;
      }
    }

    const graph = new Graph();

    const myVertices = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'];
    for(let i of myVertices){
      graph.addVertex(i);
    }
    graph.addEdge('A', 'B');
    graph.addEdge('A', 'C');
    graph.addEdge('A', 'D');
    graph.addEdge('C', 'D');
    graph.addEdge('C', 'G');
    graph.addEdge('D', 'H');
    graph.addEdge('D', 'G');
    graph.addEdge('B', 'E');
    graph.addEdge('B', 'F');
    graph.addEdge('E', 'I');

    console.log(graph)
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容