图(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)复制代码