js实现数据结构及算法之图和图算法(Graphs)

1,511 阅读3分钟

图(Graphs)

图由边的集合及顶点的集合组成,每个城市就是一个顶点,每一条道路就是一个边

顶点也有权重,也称为成本。如果一个图的顶点对是有序的,则称之为有向图。在对有向图中的顶点排序后,便可以在两个顶点之间绘制一个箭头。有向图表明了顶点的流向。流程图就是一个有向图的例子

如果图是无序的,则称之为无序图或无向图

从一个节点走到另一个节点的这一组边称为路径。路径中所有的顶点都由边连接。路径的长度用路径中第一个顶点到最后一个顶点之间边的数量表示,指向自身的顶点组成的路径称为,环的长度为0

圈是至少有一条边的路径,且路径的第一个顶点和最后一个顶点相同。无论有向图还是无向图只要是没有重复的顶点的圈就是一个简单圈,除了第一个和最后一个顶点以外,路径的其他顶点有重复的圈称为平凡圈

如果两个顶点之间有路径,那么这两个顶点之间就是强连通的,如果有向图的所有顶点都是强连通的,那么这个有向图也是强连通的

图的遍历

广度优先搜索(BFS)

从第一个顶点开始,尝试访问尽可能靠近它的顶点

深度优先搜索(DFS)

访问一个没有访问过的顶点,将他标记为已访问,再递归地去访问在初始顶点的邻接表中其他没有访问过的顶点

js实现

/**
 * 一个简单的图和图算法
 * @constructor
 */
function Graph(v) {
  this.vertices = v    //顶点
  this.edges = 0       //边
  this.adj = []          //定义数组
  this.marked = []  //标记是否已访问 false为未访问 true为访问过了
  for (var i = 0; i < this.vertices; i++) {           //定义二维数组
    this.adj[i] = []
    this.marked[i] = false
  }
  this.addEdge = addEdge  //添加顶点
  this.show = show  //显示顶点
  this.dfs = dfs      //深度优先搜索
  this.bfs = bfs      //广度优先搜索
  this.edgeTo = []  //从一个顶点到下一个顶点的所有边
  this.hasPathTo = hasPathTo //是否有路径
  this.pathTo = pathTo //最短路径
}

//添加顶点
function addEdge(v, m) {
  this.adj[v].push(m)
  this.adj[m].push(v)
  this.edges++
}

//显示顶点
function show() {
  for (var i = 0; i < this.vertices; i++) {
    var edges = ''
    for (var j = 0; j < this.vertices; j++) {
      if (this.adj[i][j]) {
        edges += this.adj[i][j] + ' '
      }
    }
    console.log(i + '->' + edges)
  }
}

//深度优先搜索
function dfs(v) {
  this.marked[v] = true
  if (this.adj[v] !== undefined) {
    console.log(v + '该节点被访问了')
  }
  for (var w in this.adj[v]) {
    var current = this.adj[v][w]
    if (!this.marked[current]) {
      this.dfs(current)
    }
  }
}

//广度优先搜索
function bfs(v) {
  var queue = []
  this.marked[v] = true
  queue.push(v)
  while (queue.length > 0) {
    var s = queue.shift()
    if (s !== undefined) {
      console.log(s + '该节点被访问了')
    }
    for (var w in this.adj[s]) {
      var current = this.adj[s][w]
      if (!this.marked[current]) {
        this.marked[current] = true
        this.edgeTo[current] = s
        queue.push(current)
      }
    }
  }
}

//是否有路径
function hasPathTo(v) {
  return this.marked[v]
}
//最短路径
function pathTo(v) {
  var source = 0
  if(!this.hasPathTo(v)) return undefined
  var path =[]
  for(var i=v; i!=source;i=this.edgeTo[i]) {
    path.push(i)
  }
  path.push(source)
  return path
}

var graph = new Graph(6)
graph.addEdge(0, 1)
graph.addEdge(0, 2)
graph.addEdge(2, 4)
graph.addEdge(1, 3)
graph.addEdge(3, 4)
graph.addEdge(3, 5)
graph.addEdge(4, 5)
graph.show()
console.log('=======深度优先搜索=========')
// graph.dfs(0)
console.log('=======广度优先搜索=========')
graph.bfs(0)
var paths = graph.pathTo(5)
var str = ''
while(paths.length>0){
  if(paths.length>1) {
    str += paths.pop()+'->'
  }else {
    str +=paths.pop()
  }
}
console.log(str)