用js来实现那些数据结构15(图01)

  其实在上一篇介绍树结构的时候,已经有了一些算法的相关内容介入。而在图这种数据结构下,会有更多有关图的算法,比如广度优先搜索,深度优先搜索最短路径算法等等。这是我们要介绍的最后一个数据结构。同时也是本系列最为复杂的一个。那么我们先来简单介绍一下,什么是图?

一、图的概念

  简单说,就是网络结构的抽象模型,图是一组由连接的节点(或顶点)。任何二元关系都可以用图来表示。比如我们的地图,地铁线路图等。都是图的实际应用。

  接着我们看看图的一些相关概念和术语。

  一个图G = (V,E)由以下元素组成:

    V:一组顶点。

    E:一组边,链接V中的顶点。

  在继续之前我们先来上张图,继续我们的看图说话。

   请看上图,我们来解释一些概念。

    1、由一条边连接在一起的顶点称为相邻顶点。比如上图中的A和B,A和C,A和D都是相邻的,但是A和E不是相邻的。

    2、一个顶点的取决于其相邻顶点的数量。也就是说,有多少个顶点与其相连,那么它的度就是多少。比如A的度是3,D的度就是4。

    3、路径是顶点V1,V2.....Vn的一个连续序列,其中Vi和Vi+1是相邻的。比如上图中的ACDG,ABEI都是一个路径。

    4、简单路径要求不包含重复的定点。比如ADG就是一条简单路径。

    5、除去最后一个顶点(因为它和第一个顶点时相同的),也是一个简单路径,比如ADCA。

    6、如果图中不存在环。则该图是无环的。

    7、如果图中每两个顶点间都存在路径,则该图是连通的。

  为了便于对比,我又花了一张图。

  跟第一幅图几乎是一样的,只不过我们在路径上加了点东西。

    8、图可以是有向的(边有方向)或者是无向的(边没有方向)。比如上图我们在边上加了方向就变成了有向图。

    9、如果在图中的两个顶点间在双向上都存在路径,则该图是强连通的。比如上图中我们可以说C和D是强连通的。A和B不是强连通的。但是上图并不是一个强连通图。因为上图并不是两个点都有双向的路径。

    10、图还可以是未加权的或是加权的。上图边上加的数字就是加权值。(加权的意思可以简单理解为CSS选择器中的那种权重。)

二、图的表示方法

  我们可以表示图的方法有很多。根据我们要解决问题的类型和图的类型。我们可以选择不同的方法来表示图。下面我们会简单介绍两种表示图的方法。

  1、邻接矩阵。每一个节点都和一个整数相关联,该整数将作为数组的索引。我们用一个二维数组来表示各个顶点之间的连接情况。比如索引为i的节点和索引为j的节点相邻,则表示为arrya[i][j]=1。否则arrya[i][j]=0。

  邻接矩阵看起来就是这样子的。要注意我们上面的邻接矩阵只是表示两个顶点是否相邻。我们还需要一个数组来存储所有的顶点。

  但是邻接矩阵会有一些性能问题。比如我们会用很多的空间来表示一些根本就不存在的边。比如上图所有的0。再比如我们想要找到A顶点的相邻顶点,即使A顶点只有一个相邻顶点。我们也必须遍历整个数组才能找到。

2、邻接表,鉴于以上的问题。我们在本篇中所使用的图的表示方法就是邻接表。邻接表由图中每个顶点的相邻顶点列表所组成。我们可以用数组,链表,map或者hashMap来实现邻接表。

  邻接表看起来就像是上图这样。

  那么我们知道了图的一些基本概念和我们要使用的图的表示方法。下面我们先来完成我们Graph类的架子。

function Map () {
    //......其他各种方法,详见前面的字典部分
}

//代码很简单,但是还是要解释一下。
function Graph() {
    //vertices数组存放我们图中所有的顶点
    var vertices = [];
    //adjList存放我们的邻接表。adjList会使用顶点来作为键,邻接顶点列表作为值
    var adjList = new Map();
    //添加顶点的方法。
    this.addVertices = function (v) {
        //存放到顶点数组中
        vertices.push(v);
        //生成一个还没有邻接顶点列表的Map,因为这时我们已经有顶点了,所以要生成以待使用
        adjList.set(v,[]);
    }
    //这里有个小细节我们需要注意,哦对,这是为图添加边的方法。要注意的是,实际上,在代码中,我们是没有一个东西(变量或者其他什么)来代表边的。
    //我们为两个顶点之间添加一个边实际上只是为两个顶点的邻接表中加入彼此。这样就代表了这两个顶点是相邻的。
    this.addEdge = function (v,w) {
        //而这里我们所实现的图是无向图,所以需要给两个顶点所对应的邻接表加入彼此。
        //而如果是有向图的话,只需要根据方向添加一个就可以了。
        adjList.get(v).push(w);
        adjList.get(w).push(v);
    }

    // 为了方便观察,我们再实现一个toString方法
    // 没啥好说的,双重循环遍历两个数组。
    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 graph = new Graph();

var verticesArray = ['A','B','C','D','E','F','G','H','I'];

for(var i = 0; i < verticesArray.length; i++) {
    graph.addVertices(verticesArray[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());
/*
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  
*/

  那么我们就实现了Graph类中最简单的部分——如何添加顶点和边。大家会不会觉得有点简单了。嘿嘿.....有趣的还在后面,别急......

  好了,那么到这里这篇文章就结束了。下一篇文章我们再继续学习图的遍历。

  最后,由于本人水平有限,能力与大神仍相差甚远,若有错误或不明之处,还望大家不吝赐教指正。非常感谢!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Android机动车

数据结构——图相关概念

可是现实生活中,好多关系不再是一对一或一对多,比如人和人之间的关系,会互相认识,就要考虑多对多的情况。这就是今天要介绍的——图。

962
来自专栏恰同学骚年

数据结构基础温故-5.图(上):图的基本概念

前面几篇已经介绍了线性表和树两类数据结构,线性表中的元素是“一对一”的关系,树中的元素是“一对多”的关系,本章所述的图结构中的元素则是“多对多”的关系。图(Gr...

922
来自专栏从流域到海域

图(Graph)的常用代码集合

图的相关概念请查阅离散数学图这一章或者数据结构中对图的介绍。代码来自课本。 /*Graph存储结构*/ //邻接矩阵表示法 #define MAX_VERTEX...

3156
来自专栏用户画像

5.3.2 深度优先搜索(Depth-First-Search,DFS)

与广度优先搜索不同,深度优先搜索(DFS)类似于树的先序遍历。正如其名称中所暗含的意思一样,这种搜索所遵循的搜索策略是尽可能“深”地搜索一个图。它的基本思想如下...

853
来自专栏python读书笔记

《python算法教程》Day5 - DFS遍历图(邻接字典)DFS简介代码示例

这是《python算法教程》的第5篇读书笔记。这篇笔记的主要内容为运用DFS(深度优先搜索,depth first search)对图(邻接字典)进行遍历。 D...

46911
来自专栏云霄雨霁

加权无向图----加权无向图的实现

1660
来自专栏编程理解

数据结构(八):邻接表与邻接矩阵

邻接表和邻接矩阵是图的两种常用存储表示方式,用于记录图中任意两个顶点之间的连通关系,包括权值。

1532
来自专栏mathor

LeetCode218. 天际线问题

 如果按照一个矩形一个矩形处理会非常麻烦,我们把这些矩形拆成两个点,一个左上角顶点,一个右上角顶点。将所有顶点按照横坐标进行排序然后开始遍历,遍历时通过一个...

1022
来自专栏calmound

HDU 3652 B-number(数位DP)

http://acm.hdu.edu.cn/showproblem.php?pid=3652 题意:类似3555,0-n之间某个数中包含13,且整个数能被13...

3326
来自专栏尾尾部落

[剑指offer] 跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

762

扫码关注云+社区