资讯详情

七、图结构

七、图结构

7.1 图的简介

图是什么?

  • 是一种与有些的数据结构

  • 是数学的一个,而且在数学中,的一种

  • 图论以,研究组成的的数学

  • 主要研究目的如下:系,顶点代表,边代表

图的特点

  • 一组:通常用的集合

  • 一组:通常用的集合

    • 之间的连线

    • 边可以是是的,也可以的。比如

图中常用术语

  • 顶点:表示图中的

  • 边:表示连间的连接;

  • 相邻顶点:由的顶点称为

  • 度:顶点度是

  • 路径:

    • :路径要求简单的顶点;

    • 路径称为回路;

  • 无向图:图中的一切的;

  • 向图:图中的一切的;

  • 无权图:中的边

  • 带权图:中的边

7.2 图的表示

邻接矩阵

表示图的常用方法是:

  • 可以使用表示邻接矩阵;

  • 邻接矩阵让相关联,该值;

  • 使用一个来表示

![C{@7N35Q7(OYKA_JGA0(Y(O.jpg](https://img-blog.csdnimg.cn/img_convert/a6ac96f71ae9804543da0f43c187974b.jpeg#clientId=uc8b0f51c-0f19-4&crop=0&crop=0&crop=1&crop=1&from=drop&id=uafa1b564&margin=[object Object]&name=C{@7N35Q7(OYKA_JGA0(Y(O.jpg&originHeight=517&originWidth=1024&originalType=binary&ratio=1&rotation=0&showTitle=false&size=40596&status=done&style=none&taskId=u0cacc789-6b90-4194-901e-27b1de6db6b&title=)

如上图所示:

  • 二维数组

  • 如:,表示 A 和 C 之间有

  • 邻接矩阵的,表示(与自己没有联系);

  • 若为,则

邻接矩阵的问题

若图为一,然后邻接矩阵中将,造成**浪费存储空间 **

邻接表

另一种常用的表示图方式是:

  • 图中有邻接表组成;

  • 这个列表是可用的,比如:**数组/链表/字典(哈希表)**等都可以;

![AMMKaTeX parse error: Expected 'EOF', got '}' at position 1: }?5Y5H(`J5JP4EHG}…}5Y5H(`J5JP4EHG}V]Y.jpg&originHeight=632&originWidth=1024&originalType=binary&ratio=1&rotation=0&showTitle=false&size=40721&status=done&style=none&taskId=u300123d3-932d-408e-a18d-c81e420def0&title=&width=540)

如上图所示:

  • 图中可清晰看到,如果要表示这些与A顶点相邻的顶点(边),可以通过

  • 之后,通过取出相应的数据非常方便;

邻接表的问题

  • 邻接表可以简单得到,也就是说,一个顶点指向其他顶点的数量;

  • 但是,计算邻接表(指向某一顶点的其他顶点的数量称为该顶点的入度)非常困难。此时需要结构有效计算入度;

7.3 封装图结构

在实现过程中使用表示边的方式,使用存储邻接表

添加字典类和队列类

首先,需要引入以前实现的字典和队列

///包装字典 function Dictionary() { 
         //字典属性 this.items = { 
         } //字典操作方法 //一.在字典中添加键值对 Dictionary.prototype.set = function (key, value) { 
          this.items[key] = value } //二.判断字典中是否有某个key Dictionary.prototype.has = function (key) { 
          return this.items.hasOwnProperty(key) } //三.从字典中移除元素 Dictionary.prototype.remove = function (key) { 
          //1.判断字典中是否有这个key if (!this.has(key)) return false //2.从字典中删除key delete this.items[key] return true } //四.根据key获取value Dictionary.prototype.get = function (key) { 
          return this.has(key) ? this.items[key] : undefined } //五.获取所有keys Dictionary.prototype.keys = function () { 
          return Object.keys(this.items) } //六.size方法 Dictionary.prototype.keys = function () { 
          return this.keys().length } //七.clear方法 Dictionary.prototype.clear = function () { 
          this.items = { 
         } } } //封装队列类 function Queue() { 
          //属性 this.items = [] //方法 //1.enqueue Queue.prototype.enqueue = (element) => { 
          this.items.push(element) } //2.dequeue Queue.prototype.dequeue = () => { 
          return this.items.shift() } //3.front Queue.prototype.front = () => { 
          return this.items[0] } //4.isEmpty Queue.prototype.isEmpty = () => { 
          return this.items.length === 0 } //5.size Queue.prototype.size = () => { 
          return this.items.length } //6.toString Queue.prototype.toString = () => { 
          return this.items.join('') } } 

创建图类

function Graph (){ 
        
  //属性:顶点(数组)/边(字典)
  this.vertexes = []//顶点
  this.edges = new Dictionary()//边
}

添加顶点与边

创建一个;创建一个,其中。 代码实现:

Graph.prototype.addVertex = function (v) { 
        
  this.vertexes.push(v)
  this.edges.set(v, [])
}
Graph.prototype.addEdge = (v1,v2){ 
        
  this.edges.get(v1).push(v2)
  this.edges.get(v2).push(v1)
}

测试代码:

let graph = new Graph()
let myVertexes = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']
for (let i = 0; i < myVertexes.length; i++) { 
        
  graph.addVertex(myVertexes[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)

测试结果:

![image.png](https://img-blog.csdnimg.cn/img_convert/67d982fee42e552f4c15fd97d3f2dbe0.png#clientId=uc8b0f51c-0f19-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=205&id=ub1bc864a&margin=[object Object]&name=image.png&originHeight=410&originWidth=740&originalType=binary&ratio=1&rotation=0&showTitle=false&size=31376&status=done&style=none&taskId=ud4a1859d-51ce-4353-b67b-fb4138ce758&title=&width=370)

![}A0G3MSGZVU0HVN%60825F4.jpg](https://img-blog.csdnimg.cn/img_convert/466dd0ba2430ed808de7f788e3a848d3.jpeg#clientId=uc8b0f51c-0f19-4&crop=0&crop=0&crop=1&crop=1&from=drop&id=ud12c64b7&margin=[object Object]&name=}A0G3MSGZVU0HVN%60825F4.jpg&originHeight=790&originWidth=1024&originalType=binary&ratio=1&rotation=0&showTitle=false&size=42517&status=done&style=none&taskId=uf63df957-6b16-4464-a7dc-9b9ae5884a3&title=)

转换为字符串输出

为图类Graph添加

代码实现:

Graph.prototype.toString = () => { 
        
  let resultString = ''
  for (let i = 0; i < this.vertexes.length; i++) { 
        
    resultString += this.vertexes[i] + ' ---> '
    let vEdge = this.edges.get(this.vertexes[i])
    for (let j = 0; j < vEdge.length; j++) { 
        
      resultString += vEdge[j] + ' '
    }
    resultString += '\n'
  }
  return resultString
}

测试代码:

console.log(graph.toString())

测试结果:

![image.png](https://img-blog.csdnimg.cn/img_convert/f8381cd6c3bc340535447e6bc8c8513d.png#clientId=ua8b1b9d2-e898-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=307&id=u345154f6&margin=[object Object]&name=image.png&originHeight=218&originWidth=210&originalType=binary&ratio=1&rotation=0&showTitle=false&size=4587&status=done&style=none&taskId=u310074bb-620d-4e81-8ca5-cb4d34283e3&title=&width=296)

图的遍历

  • 图的遍历思想:

    • 图的遍历思想与树的遍历思想一样,意味着需要
  • 遍历图的两种算法

  • 两种遍历算法都需要

  • 为了记录顶点是否被访问过,使用三种颜色来表示他们的状态

    • 白色:表示该顶点还访问过

    • 灰色:表示该顶点访问过,但其顶点访问过

    • 黑色:表示该顶点过,且其相邻顶点都

首先封装initializeColor方法,将图中所有顶点初始化为白色,代码实现如下

Graph.prototype.initializeColor = () => { 
        
  let colors = []
  for (let i = 0; i < this.vertexes.length; i++) { 
        
    colors[this.vertexes[i]] = 'white'
  }
  return colors
}

广度优先搜索

  • 广度优先搜索算法会从指定的,先,就像一次访问图的一层

  • 也可以说是的遍历图中的各个顶点

![5MHP8)ZKaTeX parse error: Expected 'EOF', got '#' at position 99: …39837afea8.jpeg#̲clientId=ua8b1b…GPW1IF`B0TG4XYW.jpg&originHeight=687&originWidth=1024&originalType=binary&ratio=1&rotation=0&showTitle=false&size=48469&status=done&style=none&taskId=u77ca0b46-99a1-4fe0-8144-db7da85ab44&title=)

实现思路:

基于队列可以简单地实现广度优先搜索算法:

  • 首先创建一个

  • 调用封装的initializeColor方法将所有

  • 指定,将A标注为(被访问过的节点),并将A放入队列Q中;

  • 循环遍历队列中的元素,只要队列Q非空,就执行以下操作:

    • 先将出;

    • 取出A后,将依次从队列。以此保证,灰色的相邻顶点不重复加入队列;

    • A的节点加入Q后,,在下一次循环中被

代码实现:

Graph.prototype.bfs = (initV, handler) => { 
        
  let colors = this.initializeColor()
  let que = new Queue()
  que.enqueue(initV)
  while(!que.isEmpty()){ 
        
    let v = que.dequeue()
    let vNeighbours = this.edges.get(v)
    colors[v] = 'gray'
    for (let i = 0; i < vNeighbours.length; i++) { 
        
      const a = vNeighbours[i]
      if(colors[a] == 'white'){ 
        
        colors[a] = 'gray'
        que.enqueue(a)
      }
    }
    handler(v)
    colors[v] = 'black'
  }
}

测试代码:

//4.测试bfs遍历方法
let result = ""
graph.bfs(graph.vertexes[0], function(v){ 
        
  result += v + "-"
})
console.log(result);

测试结果:

![image.png](https://img-blog.csdnimg.cn/img_convert/a83268143dc9c3af2606f3da324df4b1.png#clientId=ua8b1b9d2-e898-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=316&id=ua76fad42&margin=[object Object]&name=image.png&originHeight=260&originWidth=255&originalType=binary&ratio=1&rotation=0&showTitle=false&size=6328&status=done&style=none&taskId=ub8811968-849a-4282-b2ea-56c993574e8&title=&width=309.5)

深度优先搜索

  • 深度优先搜索算法会从指定的,沿着

  • 接着,并

![NX%HQLWDKH@GPYL47%38V.jpg](https://img-blog.csdnimg.cn/img_convert/26b13968b5b544a08d02c54eb8a396d2.jpeg#clientId=ua8b1b9d2-e898-4&crop=0&crop=0&crop=1&crop=1&from=drop&id=ub120d94c&margin=[object Object]&name=NX%HQLWDKH@GPYL47%38V.jpg&originHeight=771&originWidth=1024&originalType=binary&ratio=1&rotation=0&showTitle=false&size=46584&status=done&style=none&taskId=u7e150b86-9341-44b8-b887-02cff816086&title=)

实现思路:

  • 可以使用深度优先搜索算法;

  • 深度优先搜索算法的遍历顺序与二叉搜索树中的先序遍历较为相似,同样可以(递归的本质就是函数栈的调用)。

  • 基于递归实现深度优先搜索算法:定义用于调用递归,定义用于

  • 中:

    • 首先,调用

    • 然后,调用

  • 中:

    • 首先,将传入的指定节点**v标注为灰色;

**

  • 接着,

  • 然后,访问

  • 最后,将顶点

代码实现:

Graph.prototype.bfs = (initV, handler) => { 
        
  let colors = this.initializeColor()
  let que = new Queue()
  que.enqueue(initV)
  while(!que.isEmpty()){ 
        
    let v = que.dequeue()
    let vNeighbours = this.edges.get(v)
    colors[v] = 'gray'
    for (let i = 0; i < vNeighbours.length; i++) { 
        
      const a = vNeighbours[i]
      if(colors[a] == 'white'){ 
        
        colors[a] = 'gray'
        que.enqueue(a)
      }
    }
    handler(v)
    colors[v] = 'black'
  }
}

测试代码:

//4.测试bfs遍历方法
let result = ""
graph.dfs(graph.vertexes[0], function(v){ 
        
  result += v + "-"
})
console.log(result);

测试结果:

![image.png](https://img-blog.csdnimg.cn/img_convert/decd9e71b90adfb9fe4dbdebec35d94d.png#clientId=ua8b1b9d2-e898-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=300&id=u407d0601&margin=[object Object]&name=image.png&originHeight=320&originWidth=544&originalType=binary&ratio=1&rotation=0&showTitle=false&size=12974&status=done&style=none&taskId=ud5d5182c-dba7-4cdd-a1b1-d9581fab660&title=&width=510)

完整实现

function Graph() { 
        
  //属性:顶点(数组)/边(字典)
  this.vertexes = []//顶点
  this.edges = new Dictionary()//边

  Graph.prototype.addVertex = function (v) { 
        
    this.vertexes.push(v)
    this.edges.set(v, [])
  }
  Graph.prototype.addEdge = (v1, v2) => { 
        
    this.edges.get(v1).push(v2)
    this.edges.get(v2).push(v1)
  }
  Graph.prototype.toString = () => { 
        
    let resultString = ''
    for (let i = 0; i < this.vertexes.length; i++) { 
        
      resultString += this.vertexes[i] + ' ---> '
      let vEdge = this.edges.get(this.vertexes[i])
      for (let j = 0; j < vEdge.length; j++) { 
        
        resultString += vEdge[j] + ' '
      }
      resultString += '\n'
    }
    return resultString
  }
  Graph.prototype.initializeColor = () => { 
        
    let colors = []
    for (let i = 0; i < this.vertexes.length; i++) { 
        
      colors[this.vertexes[i]] = 'white'
    }
    return colors
  }
  Graph.prototype.bfs = (initV, handler) => { 
        
    let colors = this.initializeColor()
    let que = new Queue()
    que.enqueue(initV)
    while (!que.isEmpty()) { 
        
      let v = que.dequeue()
      let vNeighbours = this.edges.get(v)
      colors[v] = 'gray'
      for (let i = 0; i < vNeighbours.length; i++) { 
        
        const a = vNeighbours[i]
        if (colors[a] == 'white') { 
        
          colors[a] = 'gray'
          que.enqueue
        标签: 集成电路lm2575hvn

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台