1. 什么是图?
 
- 图结构是一种与树结构相似的数据结构
- 图论是数学的一个分支,并且在数学的概念上,树也是图的一种
- 他以图为研究对象,研究的顶点和边组成的图形
- 主要研究事物之间的关系,顶点代表事物,边代表两个事物之间的关系
2. 图的应用场景
 
- 我们要知道树结构有很多应用场景,比如公司的架构、家族的关系等
- 图结构的话,有人与人之间的关系网,人就代表顶点,人与人之间的关系就代表边
- 科学家们在观察人与人之间关系网的时候,还发现了六度空间理论
3. 六度空间理论
 
- 你和任何一个陌生人之间所间隔的人不会超过六个
- 最多通过6个中间人你就能够认识任何一个陌生人。这就是六度分割理论,也叫小世界理论。
4. 图的特点
 
- 一组顶点:通常用V(Vertex)表示顶点的集合
- 一组边:通常用E(Edge)来表示边的集合 
  - 边是顶点与顶点之间的连线
- 边可以是有向的,也可以是无向的
- 比如A — B 通常表示无向,A --> B 通常表示有向
- 无向就是A可以到B,B可以到A,有向就是A可以到B,但B不能到A
 
5. 欧拉七桥问题
 
- 18世纪初普鲁士的哥尼斯堡,有一条河穿过,河上有两个小岛,有七座桥把两个岛与河岸联系起来。有个人提出一个问题:一个步行者怎样才能不重复、不遗漏地一次走完七座桥,最后回到出发点。
- 后来大数学家欧拉把它转化成一个几何问题——一笔画问题。他不仅解决了此问题,且给出了连通图可以一笔画的充要条件是:奇点的数目不是0个就是2个(连到一点的数目如是奇数条,就称为奇点,如果是偶数条就称为偶点,要想一笔画成,必须中间点均是偶点,也就是有来路必有另一条去路,奇点只可能在两端,因此任何图能一笔画成,奇点要么没有要么在两端)
6. 图的术语
 
- 顶点
- 边
- 相邻顶点 
   
- 度 
   
- 路径 
  - 简单路径:就是一个顶点到另一个顶点中,没有重复的顶点
- 回路:有重复的顶点
 
- 无向图 
   
- 有向图 
   
- 无权图 
   
- 带权图 
  - 边有一定的权重,这里的权重可以是任意你希望表示的数据,比如距离、花费的时间、票价等
 
7. 图的表示(存储)
 
7.1 邻接矩阵
 

 
- 邻接矩阵是采用二维数组来表示顶点之间的连线
- 在二维数组中,0表示没有连线,1表示有连线
- 邻接矩阵的问题: 
  - 邻接矩阵有一个比较严重的问题,就是如果是一个稀疏图(顶点之间的边比较少)
- 那么矩阵中将存在大量的0,需要浪费大量的空间来存储根本不存在的边
 
7.2 邻接表
 

 
- 邻接表是当前顶点和它相邻顶点组成的列表(顶点列表)
- 这个列表的存储方式有很多,数组、链表、哈希表都可以
- 邻接表的问题: 
  - 邻接图计算出度是比较简单的(出度:指向别人的数量)
- 邻接表如果需要计算入度,那么是一件非常麻烦的事情(入度:别人指向自己的数量)
- 它必须构造一个逆邻接表,才有有效的计算入度
 
8. 图的封装
 
8.1 广度优先遍历(BFS)
 

 
initializeColor() {
  let colors = {}
  
  for (let i = 0; i < this.vertexs.length; i++) {
    colors[this.vertexs[i]] = "white"
  }
  return colors
}
bfs(firstV) {
  let colors = this.initializeColor()
  
  let queue = []
  
  let resultStr = ""
  
  queue.push(firstV)
  
  colors[firstV] = "black"
  while (queue.length != 0) {
    
    let v = queue.shift()
    
    resultStr += v + " "
    
    let edges = this.edges[v]
    for (let i = 0; i < edges.length; i++) {
      
      
      if (colors[edges[i]] == "white") {
        queue.push(edges[i])
        colors[edges[i]] = "black"
      }
    }
  }
  return resultStr
}
 
8.2 深度优先遍历(DFS)
 

 
initializeColor() {
  let colors = {}
  
  for (let i = 0; i < this.vertexs.length; i++) {
    colors[this.vertexs[i]] = "white"
  }
  return colors
}
dfs(firstV) {
  let colors = this.initializeColor()
  
  let stack = []
  let resultStr = ""
  stack.push(firstV)
  colors[firstV] = "black"
  while (stack.length != 0) {
    let v = stack.pop()
    resultStr += v + " "
    let edges = this.edges[v]
    for (let i = 0; i < edges.length; i++) {
      if (colors[edges[i]] == "white") {
        stack.push(edges[i])
        colors[edges[i]] = "black"
      }
    }
  }
  return resultStr
}
 
8.3 封装图类
 
class Graph {
  constructor() {
    
    this.vertexs = []
    
    this.edges = {}
  }
  
  addVertex(v) {
    this.vertexs.push(v)
    this.edges[v] = []
  }
  
  addEdge(v1, v2) {
    
    this.edges[v1].push(v2)
    this.edges[v2].push(v1)
  }
  
  toString() {
    let resultStr = ""
    
    for (let i = 0; i < this.vertexs.length; i++) {
      let vertex = this.vertexs[i]
      resultStr += vertex + " --> "
      
      for (let j = 0; j < this.edges[vertex].length; j++) {
        let edge = this.edges[vertex][j]
        resultStr += edge + " "
      }
      resultStr += "\n"
    }
    return resultStr
  }
  
  initializeColor() {
    let colors = {}
    
    for (let i = 0; i < this.vertexs.length; i++) {
      colors[this.vertexs[i]] = "white"
    }
    return colors
  }
  
  bfs(firstV) {
    let colors = this.initializeColor()
    
    let queue = []
    
    let resultStr = ""
    
    queue.push(firstV)
    
    colors[firstV] = "black"
    while (queue.length != 0) {
      
      let v = queue.shift()
      
      resultStr += v + " "
      
      let edges = this.edges[v]
      for (let i = 0; i < edges.length; i++) {
        
        
        if (colors[edges[i]] == "white") {
          queue.push(edges[i])
          colors[edges[i]] = "black"
        }
      }
    }
    return resultStr
  }
  
  dfs(firstV) {
    let colors = this.initializeColor()
    
    let stack = []
    let resultStr = ""
    stack.push(firstV)
    colors[firstV] = "black"
    while (stack.length != 0) {
      let v = stack.pop()
      resultStr += v + " "
      let edges = this.edges[v]
      for (let i = 0; i < edges.length; i++) {
        if (colors[edges[i]] == "white") {
          stack.push(edges[i])
          colors[edges[i]] = "black"
        }
      }
    }
    return resultStr
  }
}
let graph = new Graph()
let arr = ["A", "B", "C", "D", "E", "F", "G", "H", "I"]
for (let i = 0; i < arr.length; i++) {
  graph.addVertex((arr[i]))
}
graph.addEdge("A", "B")
graph.addEdge("A", "C")
graph.addEdge("A", "D")
graph.addEdge("C", "D")
graph.addEdge("C", "G")
graph.addEdge("D", "G")
graph.addEdge("D", "H")
graph.addEdge("B", "E")
graph.addEdge("B", "F")
graph.addEdge("E", "I")
console.log(graph.toString())
console.log(graph.dfs("A"));
console.log(graph);