数据结构-无向图搜索(JavaScript)

概念

算法数据结构描述
广度优先搜索队列通过将顶点存入队列中,最先入队列的顶点先被探索
深度优先搜索通过将顶点存入栈中,顶点是沿着路径被探索的,存在新的相邻顶点就去访问

当要标注已经访问过的顶点时,我们用三种颜色来反映它们的状态。
白色:表示该顶点还没有被访问。
灰色:表示该顶点被访问过,但并未被探索过。
黑色:表示该顶点被访问过且被完全探索过。

效果图

广度优先搜索(Breadth-First Search,BFS))深度优先搜索(Depth-First Search,DFS)
广度优先搜索深度优先搜索

无向图的实现(邻接矩阵、邻接表)

JavaScript代码实现如下,其中广度优先搜索函数是 bfs,深度优先搜索函数是 dfsStack 。

邻接矩阵邻接表
在这里插入图片描述在这里插入图片描述

邻接表实现无向图

无向图的代码实现,此处,无线图的实现,采用了邻接表:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--支撑图的数据结构-->
    <script src="struct.js"></script>
</head>
<body>

</body>
<script>
function Graph() {
    var vertices = [];//点
    var adjList  = new Dictionary();//邻接表

    this.addVertex = function (v) {
        vertices.push(v);
        adjList.set(v, []);
    };
    this.addEdge   = function (v, w) {
        adjList.get(v).push(w);
        adjList.get(w).push(v);
    };
    this.toString  = function () {
        var s = '';
        for (var i = 0; i < vertices.length; i++) {
            s += vertices[i] + ' -> ';
            var neighbors = adjList.get(vertices[i]);
            for (var j = 0; j < neighbors.length; j++) {
                s += neighbors[j] + ' ';
            }
            s += '\n';
        }
        return s;
    };

    var initializeColor = function () {
        var color = [];
        for (var i = 0; i < vertices.length; i++) {
            color[vertices[i]] = 'white';
        }
        return color;
    };
    this.bfs            = function (v, callback) {
        var color = initializeColor(),
            queue = new Queue();
        queue.enqueue(v);
        while (!queue.isEmpty()) {
            var u         = queue.dequeue(),
                neighbors = adjList.get(u);
            color[u]      = 'grey';
            for (var i = 0; i < neighbors.length; i++) {
                var w = neighbors[i];
                if (color[w] === 'white') {
                    color[w] = 'grey';
                    queue.enqueue(w);
                }
            }
            color[u] = 'black';
            if (callback) {
                callback(u);
            }
        }
    };
    this.BFS            = function (v) {
        var color = initializeColor(),
            queue = new Queue(),
            d     = [],
            pred  = [];
        queue.enqueue(v);
        for (var i = 0; i < vertices.length; i++) {
            d[vertices[i]]    = 0;
            pred[vertices[i]] = null;
        }
        while (!queue.isEmpty()) {
            var u         = queue.dequeue(),
                neighbors = adjList.get(u);
            color[u]      = 'grey';
            for (i = 0; i < neighbors.length; i++) {
                var w = neighbors[i];
                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
        };
    };
    this.dfsStack       = function (v, callback) {
        var color = initializeColor(),
            stack = new Stack();
        stack.push(v);
        while (!stack.isEmpty()) {
            var u         = stack.pop(),
                neighbors = adjList.get(u);
            color[u]      = 'grey';
            for (var i = 0; i < neighbors.length; i++) {
                var w = neighbors[i];
                if (color[w] === 'white') {
                    color[w] = 'grey';
                    stack.push(w);
                }
            }
            color[u] = 'black';
            if (callback) {
                callback(u);
            }
        }
    };
    this.dfs            = function (callback) {
        var color = initializeColor();
        for (var i = 0; i < vertices.length; i++) {
            if (color[vertices[i]] === 'white') {
                dfsVisit(vertices[i], color, callback);
            }
        }
    };
    var dfsVisit        = function (u, color, callback) {
        color[u] = 'grey';
        if (callback) {
            callback(u);
        }
        var neighbors = adjList.get(u);
        for (var i = 0; i < neighbors.length; i++) {
            var w = neighbors[i];
            if (color[w] === 'white') {
                dfsVisit(w, color, callback);
            }
        }
        color[u] = 'black';
    };
    var time            = 0;
    this.DFS            = function () {
        var color = initializeColor(),
            d     = [],
            f     = [],
            p     = [];
        time      = 0;

        for (var i = 0; i < vertices.length; i++) {
            f[vertices[i]] = 0;
            d[vertices[i]] = 0;
            p[vertices[i]] = null;
        }
        for (i = 0; i < vertices.length; i++) {
            if (color[vertices[i]] === 'white') {
                DFSVisit(vertices[i], color, d, f, p);
            }
        }
        return {
            discovery: d,
            finished: f,
            predecessors: p
        };
    };
    var DFSVisit        = function (u, color, d, f, p) {
        console.log('discovered ' + u);
        color[u]      = 'grey';
        d[u]          = ++time;
        var neighbors = adjList.get(u);
        for (var i = 0; i < neighbors.length; i++) {
            var w = neighbors[i];
            if (color[w] === 'white') {
                p[w] = u;
                DFSVisit(w, color, d, f, p);
            }
        }
        color[u] = 'black';
        f[u]     = ++time;
        console.log('explored ' + u);
    };
}

function printNode(value) {
    console.log('Visited vertex: ' + value);
}


var graph      = new Graph();
var myVertices = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'];
for (var i = 0; i < myVertices.length; i++) {
    graph.addVertex(myVertices[i]);
}
graph.addEdge('A', 'B');
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], printNode);
graph.dfsStack(myVertices[0], printNode);
</script>
</html>

邻接矩阵实现无向图

无向图的代码实现,此处,无线图的实现,采用了邻接矩阵

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--支撑图的数据结构-->
    <script src="struct.js"></script>
</head>
<body>

</body>
<script>
    var matrix      = [
        //      A  B  C  D  E  F  G  H  I
        //      0  1  2  3  4  5  6  7  8
        /*A 0*/[0, 1, 1, 1, 0, 0, 0, 0, 0],
        /*B 1*/[1, 0, 0, 0, 1, 1, 0, 0, 0],
        /*C 2*/[1, 0, 0, 1, 0, 0, 1, 0, 0],
        /*D 3*/[1, 0, 1, 0, 0, 0, 1, 1, 0],
        /*E 4*/[0, 1, 0, 0, 0, 0, 0, 0, 1],
        /*F 5*/[0, 1, 0, 0, 0, 0, 0, 0, 0],
        /*G 6*/[0, 0, 1, 1, 0, 0, 0, 0, 0],
        /*H 7*/[0, 0, 0, 1, 0, 0, 0, 0, 0],
        /*I 8*/[0, 0, 0, 0, 1, 0, 0, 0, 0]
    ];
    var vertices = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'];

    function Graph(matrix, vertices) {

        this.toString = function () {
            var s = '';
            for (var i = 0; i < matrix.length; i++) {
                s += vertices[i] + ' -> ';
                for (var j = 0; j < matrix[i].length; j++) {
                    if (matrix[i][j] > 0) {
                        s += vertices[j] + ' ';
                    }
                }
                s += '\n';
            }
            return s;
        };

        var initializeColor = function () {
            var color = [];
            for (var i = 0; i < vertices.length; i++) {
                color[vertices[i]] = 'white';
            }
            return color;
        };
        this.bfs            = function (v, callback) {
            var color = initializeColor(),
                queue = new Queue();
            queue.enqueue(v);
            while (!queue.isEmpty()) {
                var u         = queue.dequeue(),
                    neighbors = matrix[u];
                color[vertices[u]]      = 'grey';
                for (var i = 0; i < neighbors.length; i++) {
                    if(neighbors[i] > 0) {
                        var w = vertices[i];
                        if (color[w] === 'white') {
                            color[w] = 'grey';
                            queue.enqueue(i);
                        }
                    }
                }
                color[vertices[u]] = 'black';
                if (callback) {
                    callback(vertices[u]);
                }
            }
        };
        this.dfsStack       = function (v, callback) {
            var color = initializeColor(),
                stack = new Stack();
            stack.push(v);
            while (!stack.isEmpty()) {
                var u         = stack.pop(),
                    neighbors = matrix[u];
                color[vertices[u]]      = 'grey';
                for (var i = 0; i < neighbors.length; i++) {
                    if(neighbors[i] > 0) {
                        var w = vertices[i];
                        if (color[w] === 'white') {
                            color[w] = 'grey';
                            stack.push(i);
                        }
                    }
                }
                color[vertices[u]] = 'black';
                if (callback) {
                    callback(vertices[u]);
                }
            }
        };
    }

    function printNode(value) {
        console.log('Visited vertex: ' + value);
    }

    var graph      = new Graph(matrix, vertices);
    //console.log(graph.toString());
    graph.bfs(0, printNode);
    graph.dfsStack(0, printNode);
</script>
</html>

输出

广度优先搜索深度优先搜索
A B C D E F G H IA D H G C B F E I

支撑图的数据结构

struct.js 栈、队列、字典

//栈
function Stack() {
    let 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.print   = function () {
        console.log(items.toString());
    };
}

//队列
function Queue() {
    let 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;
    };
    this.print   = function () {
        console.log(items.toString());
    };
}

//字典
function Dictionary() {
    var items     = {};
    this.has      = function (key) {
        return key in items;
    };
    this.set      = function (key, value) {
        items[key] = value;
    };
    this.get      = function (key) {
        return this.has(key) ? items[key] : undefined;
    };
    this.delete   = function (key) {
        if (this.has(key)) {
            delete items[key];
            return true;
        }
        return false;
    };
    this.values   = function () {
        var values = [];
        for (var k in items) {
            if (this.has(k)) {
                values.push(items[k]);
            }
        }
        return values;
    };
    this.keys     = function () {
        return Object.keys(items);
    };
    this.getItems = function () {
        return items;
    };
}

参考文献

[1] [巴西]Loiane Groner. 学习JavaScript数据结构与算法(第2版)[M]. 人民邮电出版社,2017.
[2] [日本]石田保辉,宫崎修一. 我的第一本算法书[M]. 人民邮电出版社,2018.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值