图论_图结构的基础理论知识

图结构

            1. 图也是一种常见的数据结构

            2. 图是一种和树结构由些相似的数据结构

            3. 图结构也图论,在数学的概念上,树是图的一种

            4. 图论以图为研究对象,研究顶点和边组成的图形的数学理论和方法

图结构的使用场景

            1. 人与人之间的关系网(六度空间理论)

            2. 地铁路线图

            3. 村庄间的路线图

图结构的特点

            1. 图结构中有两个重要的概念:顶点和边

            2. 一组顶点:通常用V(Vertex)表示顶点的集合

            3. 一组边:通常边用E(Edge)表示边的集合

                    边表示顶点与顶点之间的连线

                    边可以是有向的也可以是无向的

                    如:A -- B表示无向, A --> B表示有向

图结构的常见术语

            1. 顶点

            2. 边

            3. 相邻顶点:通过一条边可以连接起来的两个顶点互为相邻顶点

            4. 顶点的度:一个顶点所连的相邻顶点的个数叫做顶点的度

            5. 路径:由顶点V1, V2, ...组成的一个连续的序列叫做一条路径

                简单路径:不包含重复的顶点

                贿赂:第一个顶点和最后一个顶点相同的路径成为回路

            6. 有向图:边为有向的图

            7. 无向图:边全为无向的图

            8. 带权图:边携带一个权重的图

            9. 无权图:边没有权重的图

图的信息:

            一个图结构需要包含以下信息:

                1. 顶点的表示:

                    抽象成1 2 3... 或者A B C D...

                2. 边的表示:

                    邻接矩阵,即一个二维数组表示相邻顶点直接按的距离

                    邻接矩阵可以方便的表示有向图和无向图,带权图和无权图。

                    邻接矩阵的问题:

                        邻接矩阵中,如果用0表示无边,1表示有边,当顶点较多,边较少时,邻接矩阵就是一个稀疏矩阵,造成存储空间的浪费

                    邻接表:邻接表也是一种表示边的存储方式,作用和邻接矩阵一样

                        1. 邻接表由每个顶顶以及和顶点相邻的顶点列表组成

                    邻接表存在的问题:

                        1. 出度容易计算,入度计算比较麻烦

                            出度:一个顶点连接的相邻顶点

                            入度:连接顶点的相邻顶点

图结构的封装:

            1. 数据存储:

                1. 顶点用数组存储

                2. 边用邻接表存储

            2. 属性

                1. this.vertexs     顶点(数组)

                2. this.edges       字典

            3. 方法

                1. addVertex()      添加顶点

                2. addEdge()        添加边

                3. toString()       返回邻接表

                4. 顶点遍历

                    1. 广度优先搜索(Breadth-First Search, BFS)

                        基于队列,入队列的顶点先被访问,顺序和层序遍历一样

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

                        基于栈或递归,

                    这两种遍历算法都需要指定第一个被访问的顶点

 

图结构的代码实现:

function Graph(){
        // 图的属性
        // 1. 图的顶点(数组)
        // 2. 图的边(字典)
        this.vertexs = [];
        this.edges = {};

        // 图的方法
        // 1. 添加顶点  addVertex()
        Graph.prototype.addVertex = function(v){
            this.vertexs.push(v);
            this.edges[v] = [];
        }

        // 2. 添加边    addEdge()
        Graph.prototype.addEdge = function(v1, v2){
            if(this.edges[v1].indexOf(v2) == -1){
                this.edges[v1].push(v2);
            }
            if(this.edges[v2].indexOf(v1) == -1){
                this.edges[v2].push(v1);
            }
        }

        // 3. 打印邻接表    toString()
        Graph.prototype.toString = function(){
            var res = "";
            for(var i = 0; i < this.vertexs.length; i++){
                res = res + this.vertexs[i] + " |-->| ";
                // 这里的item为取出的邻接表中的一项(即一个数组)
                var item = this.edges[this.vertexs[i]];
                for(var j = 0; j < item.length; j++){
                    res = res + item[j] + " ";
                }
                res = res + "\n";
            }
            return res;
        }

        // 4. 颜色初始化
        Graph.prototype.initColor = function(){
            var colors = {};
            for(var k = 0; k < this.vertexs.length; k++){
                colors[this.vertexs[k]] = 'white';
            }
            return colors;
        }

        // 5. 图的遍历
        /*
            广度优先搜索(Breadth-First Search, BFS)
                基于队列,入队列的顶点先被
            深度优先搜索(Depth-First Search, DFS)
                基于栈或递归,
            这两种遍历算法都需要指定第一个被访问的顶点
        */
        // 5.1 广度优先搜索
        Graph.prototype.bfs = function(firstV){
            // 1. 初始化颜色
            var colors = this.initColor();

            // 2. 创建队列
            var q = new Queue();

            // 3. 将初始顶点压入队列
            q.enqueue(firstV);
            colors[firstV] = 'gray';

            var resultString = "";
            // 4. 循环遍历,将所有的顶点都压入队列
            while(!q.isEmpty()){
                // 4.1 取出队列头部的顶点
                var v = q.dequeue();
                // console.log(v);
                resultString += v + " ";

                // 4.2 获取这个顶点的相邻顶点
                var vList = this.edges[v];

                // 4.3 将这些顶点压入队列中
                for(var j = 0; j < vList.length; j++){
                    if(colors[vList[j]] == 'white'){
                        // 颜色为white表示未被访问过
                        q.enqueue(vList[j]);

                        // 将颜色设置为gray表示已经压入队列了
                        colors[vList[j]] = 'gray';
                    }
                }
            }

            // 5. 返回字符串
            return resultString;
        }

        // 5.2 深度优先搜索
        Graph.prototype.dfs = function(firstV, colors){
            var colors = this.initColor();
            var res = "";
            this.dfsV(firstV, colors, function(vertex){
                res += vertex + " ";
            });
            return res;
        }
        Graph.prototype.dfsV = function(v, colors, handler){
            // 1. 处理这个节点
            handler(v);
            colors[v] = 'red';

            // 2. 取出邻接表一个元素数组
            var vlist = this.edges[v];

            // 3. 依次访问取出的数组中的元素
            for(var k = 0; k < vlist.length; k ++){
                if(colors[vlist[k]] == 'white'){
                    this.dfsV(vlist[k], colors, handler);
                }
            }
            
        }
    }
View Code

 

 

             

 

posted @ 2020-02-12 18:19  CarreyB  阅读(380)  评论(0编辑  收藏  举报