您的位置:首页 > 理论基础 > 数据结构算法

数据结构 - 图

BradyCC 2019-06-15 09:57 148 查看 https://blog.csdn.net/bradycc/

数据结构 - 图,使用邻接表。
图遍历方式:

  1. 广度优先 - 优先遍历横向 - 队列
  2. 深度优先 - 优先遍历纵向 - 栈
// 栈实现
// ES5
var Stack = function() {
var items = [];  // 私有

// 栈顶添加元素
this.push = function(element) {
items.push(element);
};

// 栈顶拿出元素
this.pop = function() {
return items.pop();
};

// 检查栈顶元素
this.peek = function() {
return items[items.length - 1];
};

// 检查栈是否为空
this.isEmpty = function() {
return items.length == 0;
};

// 清除栈
this.clear = function() {
items = [];
};

// 获取栈长度
this.size = function() {
return items.length;
};

// 检查items
this.getItem = function() {
return items;
};
};

// 队列实现
// ES5
var Queue = function() {
var items = [];

// 队列入列
this.enqueue = function(element) {
items.push(element);
};

// 队列出列
this.dequeue = function() {
return items.shift();
};

// 检查队列第一个元素
this.front = function() {
return items[0];
};

// 检查队列是否为空
this.isEmpty = function() {
return items.length == 0;
};

// 获取队列长度
this.size = function() {
return items.length;
};

// 检查items
this.getItem = function() {
return items;
};
};

// 图实现 - 邻接表
// ES5
var Graph = function() {

// 顶点
var vertices = [];
// 边
var adjList = {};

// 1.添加顶点
this.addVertex = function(v) {
vertices.push(v);
adjList[v] = [];
};

// 2.添加边
this.addEdge = function(a, b) {
adjList[a].push(b);
adjList[b].push(a);
};

// 3.打印邻接表
this.print = function() {
var s = '';
for (var i in vertices) {
var dingdian = vertices[i];
s += dingdian + ' => ';
var bian = adjList[dingdian];
for (var j in bian) {
s += bian[j];
}
s += '\n';
}
console.log(s);
};

/**
* 图遍历方式:
* 1-广度优先 - 优先遍历横向 - 队列
* 2-深度优先 - 优先遍历纵向 - 栈
*
* 图遍历思路:
* 节点状态:3中
* 1. 未发现(尚未发现此节点)
* 2. 已经发现(发现其他节点连接到此,但未查找此节点连接的全部节点)
* 3. 已经探索(已经发现此节点连接的全部节点)
*
* */

// 广度优先遍历
// 初始化颜色 white-未发现 grey-已经发现 black-已经探索
var initColor = function() {
var color = {};
for (var i in vertices) {
color[vertices[i]] = 'white';
}
return color;
};
this.bfs = function(v, callback) {
// 获取初始化顶点color
var color = initColor();
// 初始化队列
var queue = new Queue();
queue.enqueue(v);

// 检查队列是否为空
while(!queue.isEmpty()) {
// 出列
var now = queue.dequeue();
// 获取所有边,遍历
var bian = adjList[now];
for (var i in bian) {
var w = bian[i];
if (color[w] == 'white') {
// 未发现顶点全部入列,并且标记未已发现
color[w] = 'grey';
queue.enqueue(w);
}
}
// 出列顶点标记为已探索
color[now] = 'black';
// 用于输出
if (callback) {
callback(now);
}
}
};

/**
* 广度优先算法
* distance - 记录d
* pred - 记录回溯路径
*
* */
this.BFS = function(v, callback) {
// 获取初始化顶点color
var color = initColor();
// 初始化队列
var queue = new Queue();
queue.enqueue(v);

// 初始化
var d = {};
var pred = {};
for (var i in vertices) {
d[vertices[i]] = 0;
pred[vertices[i]] = null;
}

// 检查队列是否为空
while(!queue.isEmpty()) {
// 出列
var now = queue.dequeue();
// 获取所有边,遍历
var bian = adjList[now];
for (var i in bian) {
var w = bian[i];
if (color[w] == 'white') {
// 未发现顶点全部入列,并且标记未已发现
color[w] = 'grey';

// 设置回溯点
pred[w] = now;
d[w] = d[now] + 1;

queue.enqueue(w);
}
}
// 出列顶点标记为已探索
color[now] = 'black';
// 用于输出
if (callback) {
callback(now);
}
}
return {
pred: pred,
d: d
};
};

// 深度优先算法 - 递归
var dfsVisite = function(u, color, callback) {
color[u] = 'grey';
var n = adjList[u];
for (var i in n) {
var w = n[i];
if (color[w] == 'white') {
dfsVisite(w, color, callback);
}
}
color[u] = 'black';
if (callback) {
callback(u);
}
};
this.dfs = function(v, callback) {
var color = initColor();
dfsVisite(v, color, callback);
};
};

var g = new Graph();
g.addVertex('A');
g.addVertex('B');
g.addVertex('C');
g.addVertex('D');
g.addVertex('E');
g.addVertex('F');

g.addEdge('A', 'B');
g.addEdge('A', 'C');
g.addEdge('A', 'D');
g.addEdge('B', 'E');
g.addEdge('B', 'F');
g.addEdge('C', 'D');

// 添加新路径
g.addEdge('D', 'F');

// 最短路径
var shortest = function(from, to) {
var s = g.BFS(from);
console.log(s);
var v = to; // 设置当前点
var path = new Stack();

while(v != from) {
path.push(v);
v = s.pred[v];  // 回溯点
}
path.push(v);

var str = '';
while (!path.isEmpty()) {
str += path.pop() + ' => ';
}

str = str.slice(0, str.length-4);
console.log(str);
};
shortest('A', 'F');
标签: