<!DOCTYPE html>
<html>
<head>
<title>邻接表</title>
<meta charset="utf-8">
<script type="text/javascript">
// 稀疏图 邻接表
class SparseGraph{
constructor(n, directed){
// n为定点数 m为边数
this.n = n;
this.m = 0;
this.directed = directed;
this.data = new Array();
for(var i=0; i<n; i++){
this.data[i] = new Array();
}
// 判断节点是否是访问过得
this.visited = [];
// 用来记录从哪个节点 到这个节点的值
this.from = [];
// 用来记录从源点到本节点的长度
this.ord = [];
}V() { return this.n; }
E() { return this.m; }
result() { return this.data; }
// 添加一条边
addEdge(v,w){
console.assert( v >= 0 && v < this.n);
console.assert( w >= 0 && w < this.n );// 判断v和w是否有边
if(this.hasEdge(v, w)){
return ;
}this.data[v].push(w);
if(v!=w && !this.directed){
this.data[w].push(v);
}
this.m++;
}// 判断是否有边
hasEdge(v, w){
console.assert( v >= 0 && v < this.n);
console.assert( w >= 0 && w < this.n )
return (this.data[v].length && this.data[v].indexOf(w) > 0);
}// 图的深度优先遍历
DFSTraverse(){
// 给每个节点设置 false(未遍历)
for(var i=0; i<this.n; i++){
this.visited[i] = false;
}for(var i=0; i<this.n; i++){
if(!this.visited[i]){
// console.log(i)
this.DFS(i)
}
}
}DFS(v){
// 第v个顶点 应该是访问过的
this.visited[v] = true;
console.log(v)for(var w = this.FirstAdjVex(v); w >= 0; w = this.NextAdjVex(v, w)){
// 如果v中的相邻节点没有遍历的话 那么就在遍历这个节点中的相邻节点
if(!this.visited[w]){
// 记录从哪个节点遍历 到这
this.from[w] = v;
this.visited[w] = true;
console.log(w)
// 获得w中 第一个未遍历的元素
var x = this.FirstFlase(w);
if(x >=0){
// 这个是由于 要走w的第一个元素 故要记录 x的前一个是w
this.from[x] = w;
this.DFS(x)
}
}
}
}// 获得w中的第一个未遍历的元素
FirstFlase(w){
if(this.data[w]){
for(var i=0; i<this.data[w].length; i++){
if(!this.visited[this.data[w][i]]){
return this.data[w][i];
}
}
}
return -1;
}// 图的 广度优先遍历
BFSTraverse(){
// 给每个节点设置 false (未遍历)
for(var i=0; i<this.n; i++){
this.visited[i] = false;
}// 这个循环是 为了解决图 有多个联通分量 问题
for(var i=0; i<this.n; i++){
if(!this.visited[i]){
// 实现一个队列 来广度遍历图
this.visited[i] = true;
// 把源点的长度记录为0 如果是多个联通分量,初始的节点的长度也是0
this.ord[i] = 0;
var res = []
res.push(i);
var node = null;
while(node != null || res.length>0){
var node = res.shift()
if(node != null){
console.log(node)
}
for(var w = this.FirstAdjVex(node); w >= 0; w = this.NextAdjVex(node, w)){
// 如果v中的相邻节点没有遍历的话 那么就在遍历这个节点中的相邻节点
if(!this.visited[w]){
// 如果w 未遍历 则标志改变 且加入res中
this.visited[w] = true;
this.from[w] = node;
// 这个节点到源点的长度 等于它上个节点的长度 +1
this.ord[w] = this.ord[node] + 1;
res.push(w);
}
}
}
}
}
}// 深度遍历 获得任意节点的路径
DFSPath(v, w){
// v -> w 的路径
this.DFSTraverse();return this.Path(v, w);
}
// 广度优先遍历 获得两节点之间的路径
BFSPath(v, w){
// 广度遍历
this.BFSTraverse();
return this.Path(v, w);
}//
Path(v, w){
// 存储路径
var ww = w;
var res = []while(v != w){
res.push(this.from[w])
w = this.from[w]
}
res.reverse().push(ww);
res = res.join(" -> ");return res;
}// 获得v 的 第一个连接的节点
FirstAdjVex(v){// 检测this.data[v]是否存在
if(this.data[v]){
var len = this.data[v].length;
if(len > 0){
var sum = this.data[v][0];
return sum;
}
}
return -1;
}// 获得v的下一个连接的节点
NextAdjVex(v, w){
for(var i=0; i<this.data[v].length; i++){
if(this.data[v][i] == w){
//判断v中的邻接表w的下一个节点 是否存在
return this.data[v][i+1] ? this.data[v][i+1] : -1;
}
}
return -1;
}
}
var sGraph = new SparseGraph(7, false);var wdata = [[0, 1], [0, 2], [0, 5], [0, 6], [3, 4], [3, 5], [4, 5], [4, 6]]
for(var i=0; i<wdata.length; i++){
sGraph.addEdge(wdata[i][0], wdata[i][1]);
}
console.log(sGraph.result())
//sGraph.BFSTraverse();
//sGraph.DFSTraverse()console.log(sGraph.from)
console.log(sGraph.BFSPath(0, 6))
</script>
</head>
<body></body>
</html>
数据结构之图(邻接表 稀疏图)
猜你喜欢
转载自blog.csdn.net/qq_39081958/article/details/82762938
今日推荐
周排行