美文网首页
JavaScript数据结构-图

JavaScript数据结构-图

作者: 写前端的大叔 | 来源:发表于2019-11-25 21:44 被阅读0次

概念

图是一种非线性结构,是由一组由顶点和边连接而成的。相对于二叉树更复杂些。图在日常生活中和编程中很常见,比如我们坐飞机的航班信息,导航中路径分析与计算等都是由图的数据结构组成的。如下所示就是一个图的数据结构图:


图.png

顶点

顶点是图形组成的基本元素,如图所示,A,B,C,D,E,F,G都表示顶点。

顶点与顶点之前的连线叫作边,由一条边连接在一起的顶点称为相邻顶点,一个顶点的度是其相邻顶点的数量,比如C和其他5个顶点相连,C的度为5。

路径

路径是指从点到点连续序列,如图所示,A到E的路径为ABE。

有向图和无向图

图可以分为有向图和无向图,如上图所示的图形为无向图,如果包含方向的前头就为有向图,如下所示:


有向图.png

图的表示

在数据结构中,我们有很多种表示图形的方法,最常见的主要包括邻接矩阵、邻接表。

邻接矩阵

邻接矩阵是通过使用一个二维数组来表示顶点之间的连接,如果索引为i的顶点与索引为j的顶点邻,则array[i][j]=1,如果不相邻,则array[i][j]=0。邻接矩阵如下所示:

邻接矩阵.png

邻接表

邻接表是由图中每个顶点的相信顶点列表所组成,可以通过数组、链表、字典等数据结构来表示,下图展示了邻接表的数据结构:


邻接表.png

根据每一个顶点,可以找到相邻的顶点。

代码展示

下面通过代码展示来创建图形类,添加顶点和边,该示例的代码主要使用邻接来来展示,通过一个数组 vertices来保存顶点,通过一个字典adjList来保存边如下所示:

function Graph() {
    var vertices = [];//用于保存顶点
    var adjList = [];//用于保存边,以顶点作为Key

    /*
    * 添加顶点
    * */
    this.addVertex = function (v) {
        vertices.push(v);
        adjList[v] = [];
    }

    this.addEdge = function (v,w) {
        //无向图
        adjList[v].push(w);
        adjList[w].push(v);
    }

    this.print = function () {
        var result = '';
        for (var i = 0;i<vertices.length;i++){
            var v = vertices[i];
            var edges = adjList[v];
            result += v
            result += "-->"
            if(edges){
                for (var j = 0;j<edges.length;j++){
                    result += edges[j];
                    result += " ";
                }
            }
            result += "\n";
        }
        console.log(result);
    }

}

图的遍历

图的遍历比遍历链表、二叉树要复杂很多,这里主要介绍两种方法,广度优先搜索(BFS)和深度优先搜索(DFS)。图的遍历主要要包括查找特点的顶点,查找两个顶点之前的路径,检查图是否有环等。要进行图的遍历,首先要了解这两种搜索算法的遍历算法,其核心思想是首先要找到一个初次访问的点,然后找到与该点相邻的顶点,再对每个顶点进行搜索。在搜索时,通过对顶点进行标记来记录是否搜索过,主要通过白色,灰色、红色来标记:
白色:表示该顶点还没被访问过。
灰色:表示该顶点被访问过,但没有被探索过。
红色:表示该顶点被访问过,且被完全搜索过。

广度优先

广度优先搜索是指从第一个顶点开始遍历图结构,先访问相邻的顶点,然后再一层一层的往下访问。将最上层的顶点作为V来实现广度优先算法。
1.首先创建一个队列Q
2.将V压入队列Q中。并将所有的顶点默认设置为白色
3.判断队列是否为空。
a.将U从队列中取出
b.将U的颜色设置为灰色
c.将U的邻接点入队
d.将U设置为黑色
具体代码如下所示:

    /*
    * 初始化颜色
    * */
    var initColor = function () {
        var color = [];
        for(var i = 0;i<vertices.length;i++){
            var key = vertices[i];
            color[key] = 'white';
        }
        return color;
    }

    /*
    * 广度优先搜索
    * */
    this.bfs = function (v,callback) {
        var color = initColor();
        var queue = new Queue();
        queue.enqueue(v);
        while (!queue.isEmpty()) {//一直判断队列是否为空
            var u = queue.dequeue();
            var edges = adjList[u];
            color[u] = 'gray';//访问过了
            if(edges && edges.length > 0){
                for(var i = 0;i<edges.length;i++){//遍历所有的邻接点
                    var value = edges[i];
                    if(color[value] === 'white'){
                        queue.enqueue(value);
                        color[value] = 'gray';//未被访问过的顶点在入除后时标记为灰色
                    }
                }
                color[u] = 'black';
                if(callback){
                    callback(u);
                }
            }
        }
    }

深度优先

深度优先搜索算法是从第一个指定的顶点开始遍历图,沿着路径直到最后一个顶点被访问了,再按着原路回退并搜索下一条路径。深度优先搜索算法不需要指定一个源顶点,只要出现未访问的顶点,则开始访问该顶点,搜索步骤如下所示:
1.标注顶点v是被发现的,并标记为灰色
2.将邻接点记为w,再访问顶点w
3.标记v为已被探索过的

 /*
    * 深度优先搜索
    * */
    this.dfs = function (v,callback){
        var color = initColor();
        for(var i = 0;i<vertices.length;i++){
            var value = vertices[i];
            if(color[value] === 'white'){
                dfsVisit(value,color,callback)
            }
        }
    };
    var dfsVisit = function (v,color,callback) {
        color[v] = 'gray';
        if(callback){
            callback(v);
        }
        var edgs = adjList[v];
        for(var i = 0;i<edgs.length;i++){
            var w = edgs[i];
            if(color[w] === 'white'){
                dfsVisit(w,color,callback);
            }
        }
        color[v] = 'black';
    }

具体的代码可以在源码中进行查看
个人博客

相关文章

网友评论

      本文标题:JavaScript数据结构-图

      本文链接:https://www.haomeiwen.com/subject/esdxwctx.html