前言

说到 Android 启动优化,大家第一时间可能会想到异步加载。将耗时任务放到子线程加载,等到所有加载任务加载完成之后,再进入首页。

多线程异步加载方案确实是 ok 的。但如果遇到前后依赖的关系呢。比如任务2 依赖于任务 1,这时候要怎么解决呢。

最简单的方案是将任务1 丢到主线程加载,然后再启动多线程异步加载。

如果遇到更复杂的依赖呢。

任务3 依赖于任务 2, 任务 2 依赖于任务 1 呢,这时候你要怎么解决。更复杂的依赖关系呢

总不能将任务 2,任务 3 都放到主线程加载吧,这样多线程加载的意义就不大了。

有没有更好的方案呢?

答案肯定是有的,使用有向无环图。它可以完美解决先后依赖关系。

重要概念

有向无环图(Directed Acyclic Graph, DAG)是有向图的一种,字面意思的理解就是图中没有环。常常被用来表示事件之间的驱动依赖关系,管理任务之间的调度。

顶点:图中的一个点,比如顶点 1,顶点 2。

:连接两个顶点的线段叫做边,edge。

入度:代表当前有多少边指向它。

在上图中,顶掉 1 的入度是 0,因为没有任何边指向它。顶掉 2 的入度是 1, 因为 顶掉 1 指向 顶掉 2. 同理可得出 5 的入度是 2,因为顶掉 4 和顶点 3 指向它

拓扑排序:拓扑排序是对一个有向图构造拓扑序列的过程。它具有如下特点。

  • 每个顶点出现且只出现一次。

  • 若存在一条从顶点 A 到顶点 B 的路径,那么在序列中顶点 A 出现在顶点 B 的前面

由于有这个特点,因此常常用有向无环图的数据结构用来解决依赖关系。

上图中,拓扑排序之后,任务2肯定排在任务1之后,因为任务2依赖 任务1, 任务3肯定在任务2之后,因为任务3依赖任务2。

拓扑排序一般有两种算法,第一种是入度表法,第二种是 DFS 方法。下面,让我们一起来看一下怎么实现它。

入度表法

入度表法是根据顶点的入度来判断是否有依赖关系的。若顶点的入度不为 0,则表示它有前置依赖。它也常常被称作 BFS 算法

算法思想

  • 建立入度表,入度为 0 的节点先入队

  • 当队列不为空,进行循环判断

    • 节点出队,添加到结果 list 当中

    • 将该节点的邻居入度减 1

    • 若邻居节点入度为 0,加入队列

  • 若结果 list 与所有节点数量相等,则证明不存在环。否则,存在环

实例讲解

下图所示的有向无环图,采用入度表的方法获取拓扑排序过程。

!

首先,我们选择入度为 0 的顶点,这里顶点 1 的入度为 0,删除顶点 1 之后,图变成如下。

这时候,顶点 2 和顶点 4 的入度都为 0,我们可以随便删除一个顶点。(这也就是为什么图的拓扑排序不是唯一的原因)。这里我们删除顶点 2,图变成如下:

这时候,我们再删除顶点 4,图变成如下:

选择入度为 0 的顶点 3,删除顶点 3 之后,图标称如下,

最后剩余顶点5,输出顶点5,拓扑排序过程结束。最终的输出结果为:

到此,优先无环图的入度法的流程已经讲解完毕。你清楚了嘛。

代码的话,下期会一起给出。

时间复杂度

设 AOE 网有 n 个事件,e 个活动,则算法的主要执行是:

  • 求每个事件的ve值和vl值:时间复杂度是O(n+e) ;

  • 根据ve值和vl值找关键活动:时间复杂度是O(n+e) ;

因此,整个算法的时间复杂度是O(n+e)

DFS 算法

从上面的入度表法,我们可以知道,要得到有向无环图的拓扑排序,我们的关键点要找到入度为 0 的顶点。然后接着删除该结点的相邻所有边。再遍历所有结点。直到入度为 0 的队列为空。这种方法其实是 BFS。

说到 BFS,我们第一时间就想到 DFS。与 BFS 不同的是,DFS 的关键点在于找到,出度为0的顶点。

总结如下,深度优先搜索过程中,当到达出度为0的顶点时,需要进行回退。在执行回退时记录出度为0的顶点,将其入栈。则最终出栈顺序的逆序即为拓扑排序序列。

算法思想

  • 对图执行深度优先搜索。

  • 在执行深度优先搜索时,若某个顶点不能继续前进,即顶点的出度为0,则将此顶点入栈。

  • 最后得到栈中顺序的逆序即为拓扑排序顺序。

实例讲解

同样,以下图讲解 DFS 算法的过程。

(1) 从顶点 1 开始出发,开始执行深度优先搜索。顺序为1->2->3->5。

(2)深度优先搜索到达顶点5时,顶点5出度为0。将顶点5入栈。

(3)深度优先搜索执行回退,回退至顶点3。此时顶点3的出度为0,将顶点3入栈。

(4)回退至顶点2,顶点2出度为0,顶点2入栈。

(5)回退至顶点1,顶点1可以前进位置为顶点4,顺序为1->4。

(6)顶点4出度为0,顶点4入栈。

(7)回退至顶点1,顶点1出度为0,顶点1入栈。

(8)栈的逆序为1->4->2->3->5。此顺序为拓扑排序结果。

时间复杂度

时间复杂度分析:首先深度优先搜索的时间复杂度为O(V+E),而每次只需将完成访问的顶点存入数组中,需要O(1),因而总复杂度为O(V+E)。

小结

有向无环图的拓扑排序其实并不难,难度中等。通常,我们一般使用 BFS 算法来解决,DFS 算法比较少用。

对于 BFS(入度表法),它的核心思想是

  1. 选择一个没有输入边(入度为0)的源顶点(若有多个则任选一个),

  2. 将它和它的输出边删除。重复源顶点的删除操作,直到不存在入度为0的源顶点为止。

  3. 最终,检测图中的顶点个数,若还有顶点存在则算法无解,否则顶点的删除顺序就是拓扑排序的输出顺序。

https://github.com/gdutxiaoxu/AnchorTask

如果你觉得对你有所帮助,可以关注我的微信公众号程序员徐公,下一篇,将输出 Android 启动优化(二) - 拓扑排序的原理以及解题思路

推荐阅读

致刚入职场的你 - 程序员的成长笔记

职场上这四件事,越早知道越好

拼夕夕事件反思,底层逆袭,靠拼命加班行吗

面试官:手写生产者消费者模型

Android 启动优化(一) - 有向无环图相关推荐

  1. Android 启动优化(五)- AnchorTask 1.0.0 版本正式发布了

    今天,更新一下 Android 启动优化有向无环图系列的最后一篇文章.最近一段时间,暂时不会更新这方面的文章了.系列文章汇总如下: Android 启动优化(一) - 有向无环图 Android 启动 ...

  2. 深入探索Android 启动优化(七) - JetPack App Startup 使用及源码浅析

    本文首发我的微信公众号:徐公,想成为一名优秀的 Android 开发者,需要一份完备的 知识体系,在这里,让我们一起成长,变得更好~. 前言 前一阵子,写了几篇 Android 启动优化的文章,主要是 ...

  3. 启动优化·基础论·浅析 Android 启动优化

    " [小木箱成长营]启动优化系列文章(排期中): 启动优化 · 工具论 · 启动优化常见的六种工具 启动优化 · 方法论 · 这样做启动优化时长降低 70% 启动优化 · 实战论 · 手把手 ...

  4. Android启动优化方案调研

    /   今日科技快讯   / 7月21日,国家互联网信息办公室依据<网络安全法><数据安全法><个人信息保护法><行政处罚法>等法律法规,对滴滴全球股份 ...

  5. android布局优化方案,Android启动优化-布局优化

    Android启动优化-布局优化 安卓应用开发发展到今天,已经成为一个非常成熟的技术方向,从目前的情况看,安卓开发还是一个热火朝天的发展,但高级人才却相对较少,如今移动互联网的开发者也逐渐开始注重插入 ...

  6. Android启动优化实战(有效降低APP启动时间)

    1.概述 手机点击一个APP,用户希望应用能够及时响应并快速加载.启动时间过长的应用不能满足这个期望,并且可能会令用户失望.这种糟糕的体验可能会导致用户在 Play 商店针对您的应用给出很低的评分,甚 ...

  7. Apache Spark中的有向无环图DAG

    Apache Spark中的有向无环图DAG 由DATAFLAIR TEAM ·更新· 2018年11月21日 1.目的 在本Apache Spark教程中,我们将了解Apache Spark中的DA ...

  8. C#实现有向无环图(DAG)拓扑排序

    对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在 ...

  9. 【网络流24题】D、魔术球问题(有向无环图的最小路径覆盖、思维)

    D.魔术球问题(有向无环图的最小路径覆盖.思维)[省选/NOI- ] P2765 魔术球问题 [问题分析] 枚举答案转化为判定性问题,然后最小路径覆盖,可以转化成二分图最大匹配,从而用最大流解决. [ ...

最新文章

  1. python 连接数据库对中文读取超过_python 处理中文 读取数据库输出全是问号
  2. go文件服务器mimetype,网络:什么是 MIME TYPE?
  3. Flow - JS静态类型检查工具
  4. python文件读写2
  5. QT学习:网络应用开发练习(简单网页浏览器)
  6. Log4cpp 使用手册
  7. Matlab--Monte Carlo simulation
  8. 部署web应用程序到tomcat
  9. css_input[checked]复选框去掉默认样式并添加新样式
  10. 易语言编写的档案管理系统源码_校园固定资产管理系统方案
  11. ECMAScript5新特性总结
  12. android file transfer下载_PHP通过header方式下载文件
  13. Oracle SQL存储过程结构、异常处理示例
  14. Android APP开发文档模板
  15. sql2008转到sqk2000的步骤
  16. 440页PPT华为大数据分享专场|实时|离线|数仓
  17. ztree学习笔记(一)
  18. [java学习笔记]-注解和反射
  19. 复旦961-软件工程笔记
  20. c语言运行excel中vba程序,VBA代码在WPS上可运行,在EXCEL中报错

热门文章

  1. nbu备份本机oracle,NBU异构还原Oracle完整备份的一些总结
  2. python输入学生姓名_Python练习题:由用户输入学生学号与姓名,数据用字典存储,最终输出学生信息(按学号由小到大显示)。...
  3. Flume-NG源码分析-整体结构及配置载入分析
  4. matlab中的耿贝尔法,最大降水量多年一遇计算方法及Matlab实现
  5. 物流接口,自己网上拔下来的
  6. iOS事件全面解析 (触摸事件、手势识别、摇晃事件、耳机线控)
  7. unity 对象池模式
  8. 二保焊和氩弧焊有什么区别
  9. git常用命令 提交步骤
  10. 数字化时代,如何从战略设计到架构来打造智慧银行?