JavaScript數據結構之 無向圖

/**
 * 無向圖
 *
 * 廣度優先搜索:初始化每個點的標記爲未檢查,選一個起始點入隊列,貼上待檢查標記,
 * 然後該點出隊列,尋找所有標記爲未檢查的相鄰點並將其入棧(同時修改其標記爲待檢查),
 * 對於已經出隊列的點,標記爲已檢查。終止條件:隊列爲空
 *
 * 深度優先:採用迭代的方式,類似於樹的遍歷,但是要在遍歷過程中檢查當前點是否已經並遍歷過
 */

function Graph(){
    this.vertices = [];//圖的頂點
    this.edgeList = new Map();//採用鄰接表保存邊,使用的是JavaScript的Map數據結構
}
Graph.prototype = {
    //添加頂點
    addVertex: function(value){
        this.edgeList.set(value, []);
        return this.vertices.push(value);
    },
    //添加邊,兩個方向都添加
    addEdge: function(value1, value2){
        if(!this.edgeList.get(value1))return false;
        if(!this.edgeList.get(value2))return false;
        this.edgeList.get(value1).push(value2);
        this.edgeList.get(value2).push(value1);
        return true;
    },
    //打印鄰接表到控制檯
    print: function(){
        var str = "";
        for(let i = this.vertices.length-1;i>=0;i--){
            str += this.vertices[i]+" : ";
            str += this.edgeList.get(this.vertices[i]).join(",");
            str += "\n";
        }
        console.log(str);
        return str;
    },
    //廣度優先搜索
    bfs: function(callback,start){
        //distances、predecessors用於統計最短距離
        var distances = [];//距離
        var predecessors = [];//前溯點

        start = start || this.vertices[0];
        var queue = [];
        queue.push(start);//注意,push會改變原數組,但是其返回值是新數組的長度
        var edgeList = this.edgeList;
        var isTrav = new Map();
        this.vertices.forEach(function(v){
            isTrav.set(v,0);
            distances[v] = 0;
            predecessors[v] = null;
        });

        isTrav.set(start, 1);
        while(queue.length>0){
            var u = queue.shift();
            var neighbors = edgeList.get(u);
            for(let i=0;i<neighbors.length;i++){
                var w = neighbors[i];
                if(isTrav.get(w) === 0){
                    isTrav.set(w, 1);
                    queue.push(w);
                    distances[w] = distances[u] + 1;
                    predecessors[w] = u;
                }
            }
            isTrav.set(u, 2);
            callback(u);
        }

        return {
            distances:distances,
            predecessors:predecessors
        };
    },
    //深度優先搜索
    dfs: function(callback, start){
        start = start || this.vertices[0];
        var isTrav = new Map();
        this.vertices.forEach(function(v){
            isTrav.set(v,0);
        });
        this.dfsVisit(start, isTrav, callback);
    },
    dfsVisit: function(n, isTrav, callback){
        isTrav.set(n, 1);
        callback(n);
        var neighbors = this.edgeList.get(n);
        for(let i=0;i<neighbors.length;i++){
            var w = neighbors[i];
            if(isTrav.get(w) == 0){
                this.dfsVisit(w, isTrav, callback);
            }
        }
        isTrav.set(n, 2);
    }
};


var graph = new Graph();
var myVertices = ['A','B','C','D','E','F'];
myVertices.forEach(function(v){
    graph.addVertex(v);
});
graph.addEdge('A','B');
graph.addEdge('A','C');
graph.addEdge('A','D');
graph.addEdge('C','D');
graph.addEdge('C','E');
graph.addEdge('D','E');
graph.addEdge('D','H');
graph.addEdge('B','E');
graph.addEdge('B','F');

console.log("鄰接表:");
graph.print();
console.log("廣度優先:");
var d = graph.bfs(function(v){console.log(v);});
console.log(d);
console.log("深度優先:");
graph.dfs(function(v){console.log(v);});


輸出:

鄰接表:
F : B
E : C,D,B
D : A,C,E
C : A,D,E
B : A,E,F
A : B,C,D


廣度優先:
A
B
C
D
E
F
{ distances: [ A: 0, B: 1, C: 1, D: 1, E: 2, F: 2 ],
  predecessors: [ A: null, B: 'A', C: 'A', D: 'A', E: 'B', F: 'B' ] }
深度優先:
A
B
E
C
D
F



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章