zoukankan      html  css  js  c++  java
  • 数据结构与算法之图

    定义:图由边的集合及顶点的集合组成。顶点也有权重, 也称为成本。

    如果一个图的顶点对是有序的, 则可以称之为有向图。在对有向图中的顶点对排序后, 便可以在两
    个顶点之间绘制一个箭头。 有向图表明了顶点的流向。

    1556459287978

    如果图是无序的, 则称之为无序图, 或无向图。

    1556459315157

    图中的一系列顶点构成路径, 路径中所有的顶点都由边连接。 路径的长度用路径中第一个顶点到最后一个顶点之间边的数量表示。 由指向自身的顶点组成的路径称为环, 环的长度为 0。

    圈是至少有一条边的路径, 且路径的第一个顶点和最后一个顶点相同。 无论是有向图还是无向图, 只要是没有重复边或重复顶点的圈, 就是一个简单圈。 除了第一个和最后一个顶点以外, 路径的其他顶点有重复的圈称为平凡圈。

    如果两个顶点之间有路径, 那么这两个顶点就是强连通的, 反之亦然。 如果有向图的所有的顶点都是强连通的, 那么这个有向图也是强连通的。

    表示顶点

    用Vertex类表示节点,Vertex 类有两个数据成员: 一个用于标识顶点, 另一个是表明这个顶点是否被访问过的布尔值。它们分别被命名为 label 和 wasVisited。

    function Vertex(label){
        this.label = label;
    }
    

    表示边

    用邻接表或邻接表数组来表示边。数组的索引表示顶点,元素是一个数组,里面的成员是与该顶点相连的其他顶点。因此邻接表是一个二维的数组。

    1556547359298

    构建图与搜索图

    搜索图分两种方式:深度优先和广度优先。

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

    深度优先

    深度优先搜索包括从一条路径的起始顶点开始追溯, 直到到达最后一个顶点, 然后回溯,继续追溯下一条路径, 直到到达最后的顶点, 如此往复, 直到没有路径为止。

    1556547700281

    思路:访问一个没有访问过的顶点, 将它标记为已访问, 再递归地去访问在初始顶点的邻接表中其他没有访问过的顶点。

    广度优先

    广度优先搜索从第一个顶点开始, 尝试访问尽可能靠近它的顶点。 本质上, 这种搜索在图上是逐层移动的, 首先检查最靠近第一个顶点的层, 再逐渐向下移动到离起始顶点最远的层。

    1557063097683

    用JS实现以上两种搜索方法:

    // 创建图类
    function Graph(v){
        this.vertices = v;  // 共有多少个节点
        this.edges = 0;  // 有多少条边
        this.adj = [];  // 邻接表数组
        for(var i = 0;i<this.vertices;i++){
            this.adj[i] = [];
        }
        this.marked = [];  // 用于搜索
        for(var i = 0;i<this.vertices;i++){
            this.marked[i] = false;
        }
        this.edgeTo = [];  // 用于广度优先搜索查找最短路径
    
    }
    Graph.prototype = {
        constructor: Graph,
    
        // 在两个顶点间画一条边
        addEdge(v, w){
            this.adj[v].push(w);
            this.adj[w].push(v);
            this.edges++;
        },
        showGraph(){
            for(var i = 0;i<this.vertices;i++){
                var str = '';
                for(var j = 0;j<this.vertices;j++){
                    if(this.adj[i][j] !== undefined){
                        str += this.adj[i][j] + ' ';
                    }
                }
                console.log(i + "-> " + str + '
    ');
            }
        },
    
        // 深度优先搜索函数depth first searching,递归实现
        dfs(v){
            this.marked[v] = true;
            if(this.adj[v].length){
                console.log("Visited vertex: " + v);
                for(var w of this.adj[v]){
                    if(!this.marked[w]){
                        this.dfs(w);
                    }
                }
            }
        },
    
        // 广度优先搜索函数,无递归实现
        bfs(s){
            var queue = [];
            this.marked[s] = true;
            queue.push(s);
            while(queue.length > 0){
                var v = queue.shift();
                console.log("Visited vertex: " + v);
                for(var w of this.adj[v]){
                    if(!this.marked[w]){
                        this.edgeTo[w] = v; 
                        this.marked[w] = true;
                        queue.push(w);
                    }
                }                            
            }
        }
    }
    

    利用广度优先搜索方法查找最短路径(查找顶点1和顶点4之间的最短路径):

    123

    需要再扩展一个方法,通过执行一次广度优先搜索后得到的edgeTo数组来找到1和4节点之间相互连接的节点:

    Graph.prototype.pathTo = function(w, v){
        this.bfs(w);
        var source = w;  // 顶点w作为起点
        if(!this.hasPathTo(v)){
            return undefined;
        }
        var path = [];  // 保存路径,不过是从终点到起点的
        for(var i = v; i != source; i = this.edgeTo[i]){
            path.push(i);
        }
        path.push(source);
        return path;
    }
    Graph.prototype.hasPathTo(v){
        return this.marked[v];
    }
    
    var g = new Graph(6);
    g.addEdge(0, 1);
    g.addEdge(0, 2);
    g.addEdge(1, 5);
    g.addEdge(2, 3);
    g.addEdge(3, 5);
    g.addEdge(2, 4);
    g.showGraph();
    g.pathTo(4, 1);  // [1, 0, 2, 4]
    
  • 相关阅读:
    Mybatis 原始dao CRUD方法
    JQuery的焦点事件focus() 与按键事件keydown() 及js判断当前页面是否为顶级页面 子页面刷新将顶级页面刷新 window.top.location
    使用actionerror做失败登录验证
    Java项目中的下载 与 上传
    shiro框架 4种授权方式 说明
    javascript 中数组的创建 添加 与将数组转换成字符串 页面三种提交请求的方式
    序列化表单为json对象,datagrid带额外参提交一次查询 后台用Spring data JPA 实现带条件的分页查询 多表关联查询
    Spring data JPA 理解(默认查询 自定义查询 分页查询)及no session 三种处理方法
    orcal 数据库 maven架构 ssh框架 的全注解环境模版 maven中央仓库批量删除lastupdated文件后依然是lastupdated解决方法 mirror aliyun中央仓库
    EasyUI加zTree使用解析 easyui修改操作的表单回显方法 验证框提交表单前验证 datagrid的load方法
  • 原文地址:https://www.cnblogs.com/simpul/p/11027185.html
Copyright © 2011-2022 走看看