数据结构,图结构(笔记)

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():广度优先搜索(BFS)
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():深度优先搜索(DFS)
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 = {}
  }

  // 1.addVertex(v):添加顶点
  addVertex(v) {
    this.vertexs.push(v)
    this.edges[v] = []
  }

  // 2.addEdge(v1, v2):在v1与v2之间添加边
  addEdge(v1, v2) {
    // 这里是封装的无向图
    this.edges[v1].push(v2)
    this.edges[v2].push(v1)
  }

  // 3.toString():转换字符串
  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():广度优先搜索(BFS)
  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():深度优先搜索(DFS)
  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.bfs("A"));
console.log(graph.dfs("A"));
// console.log(graph.initializeColor());

console.log(graph);
// console.log(graph.edges);
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值