数据结构(十五)之图算法

如需转载, 请咨询作者, 并且注明出处.
有任何问题, 可以关注我的微博: coderwhy, 或者添加我的微信: 372623326

在上一个章节, 我们主要是认识一下图, 并且在程序中通过代码表示了图.

这一章, 我们来学习一些图相关的算法, 我们说过: 数据结构和算法是脱离不开关系的.

一. 图的遍历

和其他数据结构一样, 我们需要可以通过某种算法来遍历结构中每一个数据.

这样可以保证, 在我们需要时, 通过这种算法来访问某个顶点的数据以及它对应的边.

遍历的方式

  • 图的遍历思想

    • 图的遍历算法的思想在于必须访问每个第一次访问的节点, 并且追踪有哪些顶点还没有被访问到.
  • 有两种算法可以对图进行遍历

    • 广度优先搜索(Breadth-First Search, 简称BFS)
    • 深度优先搜索(Depth-First Search, 简称DFS)
    • 两种遍历算法, 都需要明确指定第一个被访问的顶点.
  • 遍历的注意点:

    • 完全探索一个顶点要求我们便查看该顶点的每一条边.
    • 对于每一条所连接的没有被访问过的顶点, 将其标注为被发现的, 并将其加进待访问顶点列表中.
    • 为了保证算法的效率: 每个顶点至多访问两次.
  • 两种算法的思想:

    • BFS: 基于队列, 入队列的顶点先被探索.
    • DFS: 基于栈, 通过将顶点存入栈中, 顶点是沿着路径被探索的, 存在新的相邻顶点就去访问.
  • 为了记录顶点是否被访问过, 我们使用三种颜色来反应它们的状态:(或者两种颜色也可以)

    • 白色: 表示该顶点还没有被访问.
    • 灰色: 表示该顶点被访问过, 但并未被探索过.
    • 黑色: 表示该顶点被访问过且被完全探索过.
  • 初始化颜色代码:

    // 广度优先算法
    Graph.prototype.initializeColor = function () {
        var colors = []
        for (var i = 0; i < this.vertexes.length; i++) {
            colors[this.vertexes[i]] = "white"
        }
        return colors
    }
    

广度优先搜索

  • 广度优先搜索算法的思路:

    • 广度优先算法会从指定的第一个顶点开始遍历图, 先访问其所有的相邻点, 就像一次访问图的一层.
    • 换句话说, 就是先宽后深的访问顶点
  • 图解BFS

    img
  • 广度优先搜索的实现:

    • 创建一个队列Q.
    • 将v标注为被发现的(灰色), 并将v将入队列Q
    • 如果Q非空, 执行下面的步骤:
      • 将v从Q中取出队列.
      • 将v标注为被发现的灰色.
      • 将v所有的未被访问过的邻接点(白色), 加入到队列中.
      • 将v标志为黑色.
  • 广度优先搜索的代码:

    Graph.prototype.bfs = function (v, handler) {
        // 1.初始化颜色
        var color = this.initializeColor()
    
        // 2.创建队列
        var queue = new Queue()
    
        // 3.将传入的顶点放入队列中
        queue.enqueue(v)
    
        // 4.从队列中依次取出和放入数据
        while (!queue.isEmpty()) {
            // 4.1.从队列中取出数据
            var qv = queue.dequeue()
    
            // 4.2.获取qv相邻的所有顶点
            var qAdj = this.adjList.get(qv)
    
            // 4.3.将qv的颜色设置成灰色
            color[qv] = "gray"
    
            // 4.4.将qAdj的所有顶点依次压入队列中
            for (var i = 0; i < qAdj.length; i++) {
                var a = qAdj[i]
                if (color[a] === "white") {
                    color[a] = "gray"
                    queue.enqueue(a)
                }
            }
    
            // 4.5.因为qv已经探测完毕, 将qv设置成黑色
            color[qv] = "black"
    
            // 4.6.处理qv
            if (handler) {
                handler(qv)
            }
        }
    }
    
  • 代码解析:

    • 代码序号1: 我们先为每个顶点记录一种颜色, 用于保持它当前的状态.
    • 代码序号2: 创建队列, 这里需要用到我们之前封装的队列类型, 因此需要导入.
    • 代码序号3: 将开始的顶点放入队列中.
    • 代码序号4: 开始处理队列中的数据.
      • 4.1.先从队列中取出顶点qv.
      • 4.2.取出该顶点相邻的顶点数组qAdj.
      • 4.3.因为之前的qv已经被探测过, 所有将qv设置为灰色.
      • 4.4.遍历qAdj所有的所有的顶点, 判断颜色, 如果是白色, 那么将其将入到队列中. 并且将该顶点设置为灰色.
      • 4.5.将qv顶点设置为黑色
      • 4.6.处理qv顶点.
  • 测试代码:

    // 调用广度优先算法
    var result = ""
    graph.bfs(graph.vertexes[0], function (v) {
        result += v + " "
    })
    alert(result) // A B C D E F G H I 
    

深度优先搜索

  • 深度优先搜索的思路:

    • 深度优先搜索算法将会从第一个指定的顶点开始遍历图, 沿着路径知道这条路径最后被访问了.
    • 接着原路回退并探索吓一条路径.
  • 图解DFS:

    img
  • 深度优先搜索算法的实现:

    • 广度优先搜索算法我们使用的是队列, 这里可以使用栈完成, 也可以使用递归.
    • 方便代码书写, 我们还是使用递归(递归本质上就是函数栈的调用)
  • 深度优先搜索算法的实现:

    // 深度优先搜索
    Graph.prototype.dfs = function (handler) {
        // 1.初始化颜色
        var color = this.initializeColor()
    
        // 2.遍历所有的顶点, 开始访问
        for (var i = 0; i < this.vertexes.length; i++) {
            if (color[this.vertexes[i]] === "white") {
                this.dfsVisit(this.vertexes[i], color, handler)
            }
        }
    }
    
    // dfs的递归调用方法
    Graph.prototype.dfsVisit = function (u, color, handler) {
        // 1.将u的颜色设置为灰色
        color[u] = "gray"
    
        // 2.处理u顶点
        if (handler) {
            handler(u)
        }
    
        // 3.u的所有邻接顶点的访问
        var uAdj = this.adjList.get(u)
        for (var i = 0; i < uAdj.length; i++) {
            var w = uAdj[i]
            if (color[w] === "white") {
                this.dfsVisit(w, color, handler)
            }
        }
    
        // 4.将u设置为黑色
        color[u] = "black"
    }
    
  • 代码解析:

    • 代码序号1: 初始化颜色.和广度优先搜索算法一样.
    • 代码序号2: 遍历所有的顶点, 每遍历一个顶点, 让其执行递归函数.
      • 递归代码1: 探测了u顶点, 所有u顶点的颜色设置为灰色.
      • 递归代码2: 访问u顶点, 通过回调函数传入u.
      • 递归代码3: 访问u顶点的相连的顶点, 在访问的过程中判断该顶点如果为白色, 说明未探测, 调用递归方法.
      • 递归代码4: u被探测过, 也被访问过, 将u的颜色设置为黑色.
  • 递归的代码较难理解一些, 我们这里给出一副图来帮助大家理解过程:

    img

二. 其他算法

暂时不讨论, 后续有时间补充

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • 1 序 2016年6月25日夜,帝都,天下着大雨,拖着行李箱和同学在校门口照了最后一张合照,搬离寝室打车去了提前租...
    RichardJieChen阅读 5,016评论 0 12
  • 课程介绍 先修课:概率统计,程序设计实习,集合论与图论 后续课:算法分析与设计,编译原理,操作系统,数据库概论,人...
    ShellyWhen阅读 2,160评论 0 3
  • 第一章 绪论 什么是数据结构? 数据结构的定义:数据结构是相互之间存在一种或多种特定关系的数据元素的集合。 第二章...
    SeanCheney阅读 5,660评论 0 19
  • 图是一种比线性表和树更复杂的数据结构,在图中,结点之间的关系是任意的,任意两个数据元素之间都可能相关。图是一种多对...
    Alent阅读 2,236评论 1 22
  • 我们都一样,有着同样的感情 2017年7月23日晴 大概是因为我最近老发牢骚,妈妈想让我修养身心吧,出乎意料的,...
    乔鄞阅读 248评论 2 3