带你读《图解算法小抄》七、图(1)

简介: 带你读《图解算法小抄》七、图(1)

七、

访问 www.coding-time.cn 阅读原文动画效果,体验更佳。

 

在计算机科学中, 图(graph) 是一种抽象数据类型, 旨在实现数学中的无向图和有向图概念,特别是图论领域。

 

一个图数据结构是一个(由有限个或者可变数量的)顶点/节点/点和边构成的有限集。

 

如果顶点对之间是无序的,称为无序图,否则称为有序图;

如果顶点对之间的边是没有方向的,称为无向图,否则称为有向图;

如果顶点对之间的边是有权重的,该图可称为加权图。

 image.png

Graph

1. 完整代码

Graph

export default class Graph {
  /**
   * @param {boolean} isDirected
   */
  // 构造函数,参数表示图是否是有向的
  constructor(isDirected = false) {
    this.vertices = {}; // 顶点集
    this.edges = {}; // 边集
    this.isDirected = isDirected; // 是否为有向图
  }
  /**
   * @param {GraphVertex} newVertex
   * @returns {Graph}
   */
  // 添加顶点
  addVertex(newVertex) {
    this.vertices[newVertex.getKey()] = newVertex;
    return this;
  }
  /**
   * @param {string} vertexKey
   * @returns GraphVertex
   */
  // 根据键值获取顶点
  getVertexByKey(vertexKey) {
    return this.vertices[vertexKey];
  }
  /**
   * @param {GraphVertex} vertex
   * @returns {GraphVertex[]}
   */
  // 获取顶点的邻居
  getNeighbors(vertex) {
    return vertex.getNeighbors();
  }
  /**
   * @return {GraphVertex[]}
   */
  // 获取所有的顶点
  getAllVertices() {
    return Object.values(this.vertices);
  }
  /**
   * @return {GraphEdge[]}
   */
  // 获取所有的边
  getAllEdges() {
    return Object.values(this.edges);
  }
  /**
   * @param {GraphEdge} edge
   * @returns {Graph}
   */
  // 添加边
  addEdge(edge) {
    // 尝试查找起始和结束顶点
    let startVertex = this.getVertexByKey(edge.startVertex.getKey());
    let endVertex = this.getVertexByKey(edge.endVertex.getKey());
    // 如果起始顶点未插入,插入起始顶点
    if (!startVertex) {
      this.addVertex(edge.startVertex);
      startVertex = this.getVertexByKey(edge.startVertex.getKey());
    }
    // 如果结束顶点未插入,插入结束顶点
    if (!endVertex) {
      this.addVertex(edge.endVertex);
      endVertex = this.getVertexByKey(edge.endVertex.getKey());
    }
    // 检查边是否已经添加过
    if (this.edges[edge.getKey()]) {
      throw new Error('边已经被添加过了');
    } else {
      this.edges[edge.getKey()] = edge;
    }
    // 将边添加到顶点中
    if (this.isDirected) {
      // 如果图是有向的,那么只添加到起始顶点
      startVertex.addEdge(edge);
    } else {
      // 如果图是无向的,那么添加到两个顶点
      startVertex.addEdge(edge);
      endVertex.addEdge(edge);
    }
    return this;
  }
  /**
   * @param {GraphEdge} edge
   */
  // 删除边
  deleteEdge(edge) {
    // 从边集中删除边
    if (this.edges[edge.getKey()]) {
      delete this.edges[edge.getKey()];
    } else {
      throw new Error('在图中找不到边');
    }
    // 尝试查找起始和结束顶点,并从这些顶点中删除边
    const startVertex = this.getVertexByKey(edge.startVertex.getKey());
    const endVertex = this.getVertexByKey(edge.endVertex.getKey());
    startVertex.deleteEdge(edge);
    endVertex.deleteEdge(edge);
  }
  /**
   * @param {GraphVertex} startVertex
   * @param {GraphVertex} endVertex
   * @return {(GraphEdge|null)}
   */
  // 查找边
  findEdge(startVertex, endVertex) {
    const vertex = this.getVertexByKey(startVertex.getKey());
    if (!vertex) {
      return null;
    }
    return vertex.findEdge(endVertex);
  }
  /**
   * @return {number}
   */
  // 获取图的权重(所有边的权重之和)
  getWeight() {
    return this.getAllEdges().reduce((weight, graphEdge) => {
      return weight + graphEdge.weight;
    }, 0);
  }
  /**
   * 在有向图中反转所有的边
   * @return {Graph}
   */
  reverse() {
    /** @param {GraphEdge} edge */
    this.getAllEdges().forEach((edge) => {
      // 从图和顶点中删除直边
      this.deleteEdge(edge);
      // 反转边
      edge.reverse();
      // 将反转的边重新添加到图和顶点中
      this.addEdge(edge);
    });
    return this;
  }
  /**
   * @return {object}
   */
  // 获取顶点索引
  getVerticesIndices() {
    const verticesIndices = {};
    this.getAllVertices().forEach((vertex, index) => {
      verticesIndices[vertex.getKey()] = index;
    });
    return verticesIndices;
  }
  /**
   * @return {*[][]}
   */
  // 获取邻接矩阵
  getAdjacencyMatrix() {
    const vertices = this.getAllVertices();
    const verticesIndices = this.getVerticesIndices();
    // 使用Infinity初始化矩阵,表示尚未找到从一个顶点到另一个顶点的路径
    const adjacencyMatrix = Array(vertices.length).fill(null).map(() => {
      return Array(vertices.length).fill(Infinity);
    });
    // 填充列
  vertices.forEach((vertex, vertexIndex) => {
      vertex.getNeighbors().forEach((neighbor) => {
        const neighborIndex = verticesIndices[neighbor.getKey()];
        adjacencyMatrix[vertexIndex][neighborIndex] = this.findEdge(vertex, neighbor).weight;
      });
    });
    return adjacencyMatrix;
  }
  /**
   * @return {string}
   */
  // 将图转换为字符串
  toString() {
    return Object.keys(this.vertices).toString();
  }
}

带你读《图解算法小抄》七、图(2)https://developer.aliyun.com/article/1348216?groupCode=tech_library

相关文章
|
4月前
|
算法 搜索推荐 图计算
图计算中的社区发现算法是什么?请解释其作用和常用算法。
图计算中的社区发现算法是什么?请解释其作用和常用算法。
30 0
|
5月前
|
存储 算法 测试技术
☆打卡算法☆LeetCode 133. 克隆图 算法解析
☆打卡算法☆LeetCode 133. 克隆图 算法解析
|
5天前
|
存储 算法
图的深度优先算法
图的深度优先算法
13 0
|
7天前
|
算法 数据可视化 大数据
圆堆图circle packing算法可视化分析电商平台网红零食销量采集数据
圆堆图circle packing算法可视化分析电商平台网红零食销量采集数据
35 13
|
4月前
|
算法 搜索推荐 数据挖掘
图计算中的图算法有哪些常见的类型?请举例说明每种类型的算法。
图计算中的图算法有哪些常见的类型?请举例说明每种类型的算法。
38 0
|
4月前
|
算法 搜索推荐 Java
图计算中的PageRank算法是什么?请解释其作用和计算原理。
图计算中的PageRank算法是什么?请解释其作用和计算原理。
21 0
|
4月前
|
算法 搜索推荐 Java
图计算中的图剪枝算法是什么?请解释其作用和常用方法。
图计算中的图剪枝算法是什么?请解释其作用和常用方法。
14 0
|
6月前
|
人工智能 算法 架构师
再现神作!字节算法小抄官方整版,已助1000+应届生拿到25w+年薪
2023年经济下行趋势明显,程序员出路在哪儿? 今年,毕业人数将达到1158万,导致很多公司招聘非常谨慎、要求也变得非常更高。
再现神作!字节算法小抄官方整版,已助1000+应届生拿到25w+年薪
|
6月前
|
算法 数据挖掘 知识图谱
LINE算法复现 图表示学习 基于line 算法的节点分类 聚类显示 完整代码+数据
LINE算法复现 图表示学习 基于line 算法的节点分类 聚类显示 完整代码+数据
20 0
|
6月前
|
SQL 算法 架构师
字节算法中了80%!靠着这份GitHub上的算法小抄,成功斩获Offer
前言 最近,GitHub上的算法小抄又火了!已经有不少人靠它手撕算法题,拿下了字节、腾讯等大厂offer