javascript 图的遍历 BFS DFS

BFS,DFS好文集锦

* javascript Dictionary 类 通过HashTable 分离链接法

javascript Dictionary 类 通过HashTable 分离链接法_dictionary.prototype.has-CSDN博客

* javascript queue 队列类

javascript queue 队列类_js 队列工具类-CSDN博客

* 图的遍历

 深度优先 + 广度优先

** 广度优先

当要标注已经访问过的顶点时,我们用三种颜色来反映它们的状态。

 白色:表示该顶点还没有被访问。
 灰色:表示该顶点被访问过,但并未被探索过。

 黑色:表示该顶点被访问过且被完全探索过。

以下是从顶点v开始的广度优先搜索算法所遵循的步骤。 

(1) 创建一个队列Q。
(2) 将v标注为被发现的(灰色),并将v入队列Q。
(3) 如果Q非空,则运行以下步骤: 

  (a) 将u从Q中出队列;
  (b) 将标注u为被发现的(灰色);
  (c) 将u所有未被访问过的邻点(白色)入队列; (d) 将u标注为已被探索的(黑色)。

** 深度优先

深度优先搜索算法不需要一个源顶点。在深度优先搜索算法中,若图中顶点v未访问,则访 问该顶点v。

要访问顶点v,照如下步骤做。

(1) 标注v为被发现的(灰色)。

(2) 对于v的所有未访问的邻点w:

    (a) 访问顶点w。

(3) 标注v为已被探索的(黑色)。

深度优先搜索的步骤是递归的,这意味着深度优先搜索算法使用栈来存储函数调 用(由递归调用所创建的栈)。

* ./Collection/Stack.js

/**
 * Created by Mch on 9/9/18.
 */
function Stack() {
    this.items = [];
}

Stack.prototype = {
    push: function(element) {
        this.items.push(element);
    },
    pop: function() {
        return this.items.pop();
    },
    peek: function() {
        return this.items[this.items.length-1];
    },
    isEmpty: function () {
        return this.items.length === 0;
    },
    size: function() {
        return this.items.length;
    },
    clear: function() {
        this.items = [];
    },
    print: function () {
        console.log(this.items.toString());
    }
};

exports.Stack = Stack;

* ./Collection/Graph.js

/**
 * Created by Mch on 9/2/18.
 */
var Dictionary = require('./Dictionary').Dictionary,
    Queue = require('./Queue').Queue,
    Stack = require('./Stack').Stack,
    Comparator = require('../utils/Comparator').Comparator;

function Graph() {
    this.vertices = [];
    // 邻接表由图中每个顶点的相邻顶 点列表所组成。
    this.adjList = new Dictionary(new Comparator(function(/* String */a, /* String */b) {
        return a.localeCompare(b);
    }));
    this.time = 0;
}

Graph.prototype = {
    addVertex: function(v) {
        this.vertices.push(v);
        this.adjList.set(v, []);
    },
    addEdge: function(v, w) {
        // 无向图
        this.adjList.get(v).push(w);
        this.adjList.get(w).push(v);
    },
    toString: function() {
        var s = '', g = this;
        this.vertices.forEach(function(v) {
            s += v + ' -> ';
            // neighbors
            g.adjList.get(v).forEach(function(n) {
                s += n + ' ';
            });
            s += '\n';
        });
        return s;
    },
    initializeColor: function() {
        var color = [];
        this.vertices.forEach(function(v) {
            color[v] = 'white';
        });
        return color;
    },
    /**
     * 广度优先搜索
     * @param v
     * @param callback
     */
    bfs: function(v, callback) {
        var color = this.initializeColor(),
            queue = new Queue();
        queue.enqueue(v);

        while (!queue.isEmpty()) {
            var u = queue.dequeue();
            color[u] = 'grey';
            /* neighbors */
            this.adjList.get(u).forEach(function(w) {
                if (color[w] === 'white') {
                    color[w] = 'grey';
                    queue.enqueue(w);
                }
            });
            color[u]= 'black';
            callback && callback(u);
        }
    },
    /**
     * 使用BFS寻找最短路径
     * @param v
     * @returns {{distances: Array, predecessors: Array}}
     *   从v到u的距离d[u]
     *   前溯点pred[u],用来推导出从v到其他每个顶点u的最短路径。
     * @constructor
     */
    BFS: function(v) {
        var color = this.initializeColor(),
            queue = new Queue(),
            d = [],   // 距离
            pred = []; // 前溯点
        queue.enqueue(v);

        this.vertices.forEach(function(v) {
            d[v] = 0;
            pred[v] = null;
        });
        while (!queue.isEmpty()) {
            var u = queue.dequeue();
            color[u] = 'grey';
            // neighbors
            this.adjList.get(u).forEach(function(w) {
                if (color[w] === 'white') {
                    color[w] = 'grey';
                    d[w] = d[u] + 1;
                    pred[w] = u;
                    queue.enqueue(w);
                }
            });
            color[u] = 'black';
        }
        return {
            distances: d,
            predecessors: pred
        }
    },
    dfs: function(callback) {
        var color = this.initializeColor(), g = this;
        this.vertices.forEach(function(v) {
            if (color[v] === 'white') {
                g.dfsVisit(v, color, callback);
            }
        });
    },
    dfsVisit: function(u, color, callback) {
        color[u] = 'grey';
        callback && callback(u);
        var g = this;
        // neighbors
        this.adjList.get(u).forEach(function(w) {
            if (color[w] === 'white') {
                g.dfsVisit(w, color, callback);
            }
        });
        color[u] = 'black';
    },
    DFS: function() {
        var color = this.initializeColor(),
            d = [],
            f = [],
            p = [],
            g = this;
        this.time = 0;

        this.vertices.forEach(function(v) {
            f[v] = 0;
            d[v] = 0;
            p[v] = null;
        });
        this.vertices.forEach(function(v) {
           if (color[v] === 'white') {
               g.DFSVisit(v, color, d, f, p);
           }
        });
        return {
            discovery: d,
            finished: f,
            processors: p
        }
    },
    DFSVisit: function(u, color, d, f, p) {
        console.log('discovered ' + u);
        color[u] = 'grey';
        d[u] = ++this.time;
        var g = this;
        /* neighbor */
        this.adjList.get(u).forEach(function(w) {
            if (color[w] === 'white') {
                p[w] = u;
                g.DFSVisit(w, color, d, f, p);
            }
        });
        color[u] = 'black';
        f[u] = ++this.time;
        console.log('explored ' + u);
    }
};

Graph.printNode = function(value) {
    console.log('visited vertex: ' + value);
};

exports.Graph = Graph;

* TestGraph.js

/**
 * Created by Mch on 9/2/18.
 */
var Graph = require('./Collection/Graph').Graph;

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

graph.addEdge('A', 'B'); //{9}
graph.addEdge('A', 'C');
graph.addEdge('A', 'D');
graph.addEdge('C', 'D');
graph.addEdge('C', 'G');
graph.addEdge('D', 'G');
graph.addEdge('D', 'H');
graph.addEdge('B', 'E');
graph.addEdge('B', 'F');
graph.addEdge('E', 'I');

console.log(graph.toString());

graph.bfs(myVertices[0], Graph.printNode);

var shortestPathA = graph.BFS(myVertices[0]);
console.log(shortestPathA);

console.log('--------------------------');
graph.dfs(Graph.printNode);

var result = graph.DFS();
console.log(result);

* run:

$ node TestGraph.js
A -> B C D
B -> A E F
C -> A D G
D -> A C G H
E -> B I
F -> B
G -> C D
H -> D
I -> E

visited vertex: A
visited vertex: B
visited vertex: C
visited vertex: D
visited vertex: E
visited vertex: F
visited vertex: G
visited vertex: H
visited vertex: I
{ distances: [ A: 0, B: 1, C: 1, D: 1, E: 2, F: 2, G: 2, H: 2, I: 3 ],
  predecessors:
   [ A: null,
     B: 'A',
     C: 'A',
     D: 'A',
     E: 'B',
     F: 'B',
     G: 'C',
     H: 'D',
     I: 'E' ] }
--------------------------
visited vertex: A
visited vertex: B
visited vertex: E
visited vertex: I
visited vertex: F
visited vertex: C
visited vertex: D
visited vertex: G
visited vertex: H
discovered A
discovered B
discovered E
discovered I
explored I
explored E
discovered F
explored F
explored B
discovered C
discovered D
discovered G
explored G
discovered H
explored H
explored D
explored C
explored A
{ discovery: [ A: 1, B: 2, C: 10, D: 11, E: 3, F: 7, G: 12, H: 14, I: 4 ],
  finished: [ A: 18, B: 9, C: 17, D: 16, E: 6, F: 8, G: 13, H: 15, I: 5 ],
  processors:
   [ A: null,
     B: 'A',
     C: 'A',
     D: 'C',
     E: 'B',
     F: 'B',
     G: 'D',
     H: 'D',
     I: 'E' ] }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fareast_mzh

打赏个金币

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值