adodo0829 / blog

搭建知识体系
29 stars 4 forks source link

#102

Open adodo0829 opened 2 years ago

adodo0829 commented 2 years ago
/**
 * 图: 一组节点, 通过边连接
 * G=(V, E)
 * V:一组顶点
 * E:一组边,连接 V 中的顶点
 * 特性:
 * 相邻顶点: 一条边连接在一起的顶点称为相邻顶点;
 * 顶点的度: 是其相邻顶点的数量;
 * 路径: 是顶点 v1, v2, …, vk的一个连续序列
 * 简单路径: 要求不包含重复的顶点;
 * 环: 是一个简单路径,比如 A D C A, 图中每两个顶点间都存在路径,则该图是连通的
 * 方向性: 有向和无向
 */

// 图的数据结构表示:
// 1.邻接矩阵, 每个节点都和一个整数相关联,该整数将作为数组的索引
// 用一个二维数组来表示顶点之间的连接。如果索引为 i 的节点和索引为 j 的节点相邻,则array[i][j] === 1,否则 array[i][j] === 0

// 2.邻接表, 邻接表由图中每个顶点的相邻顶点列表所组成

// 3.关联矩阵, 矩阵的行表示顶点,列表示边; 使用二维数组来表示两者之间的连通性
// 顶点是边的入射点, array[i][j] === 1

class ValuePair {
  constructor(key, value) {
    this.key = key;
    this.value = value;
  }
  toString() {
    return `[#${this.key}: ${this.value}]`; // 要保存原始的 key value
  }
}

class Dictionary {
  constructor(toStrFn = defaultToString) {
    this.table = {};
    this.toStrFn = toStrFn; // 键: 字符串化
  }

  set(key, value) {
    // 入参检测
    if (key != null && value != null) {
      const tkey = this.toStrFn(key)
      this.table[tkey] = new ValuePair(key, value)
    }
    return false
  }

  remove(key) {
    if (this.hasKey(key)) {
      delete this.table[this.toStrFn(key)]
      return true
    }
    return false
  }

  hasKey(key) {
    return this.table[this.toStrFn(key)] != null;
  }

  get(key) {
    if (this.hasKey(key)) return this.table[this.toStrFn(key)].value
    return null
  }

  keys() {
    return this.keyValues.map(item => item.key)
  }
  values() {
    return this.keyValues.map(item => item.value)
  }
  keyValues() {
    return Object.values(this.table)
  }
  forEach(cb) {
    const kvArr = this.keyValues()
    for (let i = 0; i < kvArr.length; i++) {
      const res = cb(kvArr[i].key, kvArr[i].value)
      if (res === false) {
        break
      }
    }
  }
  clear() {
    this.table = {}
  }
  size() {
    return this.keyValues.length
  }
  isEmpty() {
    return this.size() === 0
  }
}

class Graph {
  constructor(isDirected = false) {
    this.isDirected = isDirected; // 默认无向
    // 邻接表实现
    this.vertices = []; // 顶点表
    this.adjList = new Dictionary(); // 相邻顶点表
  }

  // 添加顶点
  addVertex(v) {
    if (this.vertices.includes(v)) return;
    this.vertices.push(v);
    this.adjList.set(v, []);
  }

  // 添加邻接顶点, 边
  addEdge(v, w) {
    if (!this.adjList.get(v)) {
      this.addVertex(v);
    }
    if (!this.adjList.get(w)) {
      this.addVertex(w);
    }
    this.adjList.get(v).push(w); // w 加到 v 的邻接表里

    if (!this.isDirected) { // 无向
      // 添加 w 到 v 的边
      this.adjList.get(w).push(v);
    }
  }

  getVertices() {
    return this.vertices;
  }

  getAdjList() {
    return this.adjList;
  }

  toString() {
    let res = "";
    for (let i = 0; i < this.vertices.length; i++) {
      const v = this.vertices[i];
      res += `${v} -> `;
      const linkList = this.adjList.get(v);
      // console.log(linkList)
      for (let j = 0; j < linkList.length; j++) {
        const w = linkList[j];
        res += `${w} `;
      }
      res += "\n";
    }
    return res;
  }
}

let g = new Graph();
const edgeList = ["A", "B", "C", "D", "E", "F", "G", "H", "I"];
for (let i = 0; i < edgeList.length; i++) {
  g.addVertex(edgeList[i]);
}
g.addEdge("A", "B");
g.addEdge("A", "C");
g.addEdge("A", "D");
g.addEdge("C", "D");
g.addEdge("C", "G");
g.addEdge("D", "G");
g.addEdge("D", "H");
g.addEdge("B", "E");
g.addEdge("B", "F");
g.addEdge('E', 'I');

// console.log(g.toString())

module.exports = {
  Graph
}