表示刚知道原来js也有出数据结构的书的时候,终于把放下1年又无数次想看奈何被java挡住门外的数据结构,重新被我“宠幸”了。以前都只知道原理但是怎么敲还是一点都不知道,看了书之后。。。写法真的和java有一定出入。不过大一也没认真学java所以对我影响也不大,哈哈~~
今天看了图这一章,贴贴代码,梳理梳理。
代码全都在最后的最终代码!!!
一:表示顶点
图是由边的集合及顶点的集合组成的。
function Vertex(label,wasVisited) { //表示顶点
this.label = label; //标识顶点
this.wasVisited = wasVisited; //是否被访问了
}
我们将所有定点保存在数组中,在图类里,可以通过他们在数组中的位置引用他们。
二:表示边
表示图的边方法称为:邻接表。将边存储为由顶点的相邻顶点列表构成的数组,并以此顶点作为索引。
三:构建表
使用一个长度与图的顶点数相同的数组来记录顶点的数量。通过for循环为数组中的每个元素添加一个子数组来储存所有的相邻顶点,并将所有元素初始化为空字符串。
下面是重头戏,搜索图。
搜索分两种,深度优先搜索 和 广度优先搜索
深度优先搜索(function dfs(v) {}):访问一个没有访问过的顶点,将他标记为已访问,再递归的访问在初始顶点的邻接表中其他没有访问过的顶点。
广度优先搜索(function bfs(s) {}):从第一个顶点开始访问尽可能靠近它的顶点。本质上,这种搜索在图上是逐层移动的,首先检查最靠近第一个顶点的层,再逐层向下移。
四:最短路径
寻找从一个顶点到另一个顶点的最短路径,一般就是广度优先搜索。因为广度优先搜索会自动查找从一个顶点到另一个相连顶点的最短路径。
需要一个数组来保存从一个顶点到下一个顶点的所有边。
*bfsMin()和pathTo()
五:拓扑排序
拓扑排序会对有向图的所有顶点进行排序,使有向边从前面的顶点指向后面的顶点。
*topSort()和topSortHelper()
最终代码
function Vertex(label,wasVisited) { //表示顶点
this.label = label;
this.wasVisited = wasVisited;
}
function Graph(v) {
this.vertices = v;
this.edges = 0;
this.adj = [];
this.marked = []; //顶点是否已经被访问
for(var i = 0; i < this.vertices; ++i) {
this.adj[i] = [];
this.adj[i].push("");
this.marked[i] = false;
}
this.edgeTo = []; //保存从一个顶点到下一个顶点的所有边
this.vertexList = [];
this.addEdge = addEdge;
this.toString = toString;
this.showGraph = showGraph;
this.dfs = dfs;
this.bfs = bfs;
this.bfsMin = bfsMin;
this.pathTo = pathTo;
this.hasPathTo = hasPathTo;
this.topSort = topSort;
this.topSortHelper = topSortHelper;
}
function addEdge(v,m) {
this.adj[v].push(m);
this.adj[m].push(v);
this.edges++;
}
function showGraph() {
for(var i = 0; i < this.vertices; ++i) {
var str = "";
str += (i + "->");
for(var j = 0; j < this.vertices; ++j) {
if(this.adj[i][j] != undefined) {
str += (this.adj[i][j] + " ");
}
}
console.log(str);
}
}
function dfs(v) { //深度优先搜索函数
this.marked[v] = true;
if(this.adj[v] != undefined) {
console.log("Visited vertex:" + v);
for(var w in this.adj[v]) {
var c = this.adj[v][w];
if(!this.marked[c]) {
this.dfs(c);
}
}
}
}
function bfs(s) { //广度优先搜索函数
var queue = [];
this.marked[s] = true;
queue.push(s) //添加到队尾
while(queue.length > 0) {
var v = queue.shift(); //从队首移除
if(this.adj[v] != undefined) {
console.log("Visited vertex:" + v);
}
for(var w in this.adj[v]) {
var c = this.adj[v][w];
if(!this.marked[c]) {
this.marked[c] = true;
queue.push(c);
}
}
}
}
//广度优先搜索对应的最短路径
function bfsMin(s) {
var queue = [];
this.marked[s] = true;
queue.push(s);
while(queue.length > 0) {
var v = queue.shift();
if(v == undefined) {
console.log("Visited vertex:" + v);
}
for(var w in this.adj[v]) {
var c = this.adj[v][w];
if(!this.marked[c]) {
this.edgeTo[c] = v;
this.marked[c] = true;
queue.push(c);
}
}
}
}
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;
}
function hasPathTo(v) {
return this.marked[v];
}
//拓扑排序
function topSort() {
var stack = [];
var visited = [];
for(var i = 0; i < this.vertices; i++) {
visited[i] = false;
}
for(var i = 0; i < this.vertices; i++) {
if(visited[i] == false) {
this.topSortHelper(i,visited,stack);
}
}
for(var i = 0; i < stack.length; i++) {
if(stack[i] != undefined && stack[i] !== false) {
console.log(this.vertexList[stack[i]]);
}
}
}
function topSortHelper(v,visited,stack) {
visited[v] = true;
for(var w in this.adj[v]) {
var c = this.adj[v][w];
if(!visited[c]) {
this.topSortHelper(visited[c],visited,stack);
}
}
stack.push(v);
}
//最短路径测试
var g = new Graph(5);
g.addEdge(0,1);
g.addEdge(0,2);
g.addEdge(1,3);
g.addEdge(2,4);
g.showGraph();
g.bfsMin(0);
var vertex = 4;
var paths = g.pathTo(vertex);
console.log(paths.join("-"));
console.log("----------");
//拓扑排序测试
var g2 = new Graph(6);
g2.addEdge(1,2);
g2.addEdge(2,5);
g2.addEdge(1,3);
g2.addEdge(1,4);
g2.addEdge(0,1);
g2.vertexList = ["CS1","CS2","DATA","ASS","OPER","ALG"];
g2.showGraph();
g2.topSort();