图的定义
图由边的集合与顶点的集合组成。如果一个图的定点对是有序的则称为有向图。对有向图的顶点对排序后,可以在两个顶点之间绘制一个箭头。有向图表明了顶点的流向。
如果图是无序的则称为无序图或无向图。图中的一系列顶点构成路径,路径中的顶点都由边连接。路径的长度用第一个顶点到最后一个顶点之间边的数量表示。
由指向自身的顶点组成的路径称为环,环的长度为0。
圈是至少有一条边的路径,且路径的第一个顶点和最后一个顶点相同。没有重复顶点和重复边的圈就是一个简单的圈。除了第一个和最后一个顶点外,路径中有其他重复的顶点的圈称为平凡圈。
如果两个顶点之间有路径连通,那么这两个顶点称为强连通。
如果有向图的顶点都是强连通的那么这个图也是强连通的。
用图对现实中的系统建模
表示边
我们将表示图的边的方法称为邻接表或邻接表数组。将边表示为有顶点的相邻顶点列表构成的数组,并以此顶点作为索引。
邻接矩阵,是一个二维数组,其中的元素表示两个顶点间是否有一条边。
用一个长度与顶点数量相同的数组记录顶点,为每个元素创造一个子数组,记录相邻顶点的数量。
function Map(v) {
this.vertices = v;// 结点的总数量
this.edges = 0;
this.adj = [];
this.edgeTo = [];
this.marked = [];
for(let i = 0; i < this.vertices; i++){
this.adj[i] = [];
this.adj[i].push('');
}
for(let i = 0; i < this.vertices; i++){
this.marked[i] = false;
}
}
Map.prototype.addEdge = function (v,w){
this.adj[v].push(w);
this.adj[w].push(v);
this.edges++;
}
Map.prototype.show = function () {
for(let i = 0; i < this.vertices; i++){
for(let j = 0; j < this.vertices; j++){
if(this.adj[i][j] !== undefined){
console.log(this.adj[i][j])
}
}
}
}
Map.prototype.pathTo = function (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(s);
return path;
}
Map.prototype.hasPathTo = function (v) {
return this.marked[v];
}
搜索图
从一个指定的顶点可以到达那些顶点。
深度优先搜索
从起始顶点开始追溯,直到到达最后一个顶点,然后回溯,开始追溯下一条路径直到到达最后的顶点,如此往复,直到没有路径为止。
Map.prototype.dfs = function (v) {
this.marked[v] = true;
if(this.adj[v] !== undefined){
for(let key in this.adj[v]){
if(!this.marked[key]){
this.dfs[key];
}
}
}
}
广度优先搜索
从第一个顶点开始,尝试访问尽可能靠近它的顶点。首先检查离第一个顶点最近的层,逐渐向下移动到离第一个节点最远的层。
广度搜索使用抽象队列而不是数组对已访问过的顶点进行排序。
Map.prototype.bfs = function (s) {
let quenen = [];
this.marked[s] = true;
quenen.push(s);
while(quenen.length > 0){
let v = quenen.shift();
if(v === undefined){
console.log(v+'undefined');
}
for(let i in this.adj[v]){
if(!this.marked[i]){
this.edgeTo[i] = v;
this.marked[i] = true;
quenen.push(i);
}
}
}
}
原理
查找与当前顶点相邻的未访问顶点,将其添加到已访问顶点列表及队列中。
从图中取出下一个顶点,添加到已访问的列表顶点。
将所有与V相邻的未访问顶点添加到队列。
查找最短路径
广度优先搜索最短路径
// bfs 函数
function bfs(s) {
var queue = [];
this.marked[s] = true;
queue.push(s); //添加到队尾
while (queue.length > 0) {
var v = queue.shift(); //从队首移除
if (v == undefined) {
print("Visisted vertex: " + v);
}
for each(var w in this.adj[v]) {
if (!this.marked[w]) {
this.edgeTo[w] = v;
this.marked[w] = true;
queue.push(w);
}
}
}
}