精华内容
下载资源
问答
  • 有向无环图dag
    千次阅读
    2019-06-30 23:48:51

    目录

    1、概念:

    2、理解:

    2.1 判断是否为DAG

     2.2 出度与入度

    2.3 拓扑排序

    3、应用:


    1、概念:

    有向无环图(DAG):在有向图中,如果存在从一个顶点出发,经过若干条边无法回到该点,则称该图为有向无环图。

    2、理解:

    2.1 判断是否为DAG

    关键:判断有向图中是否存在有向环。 

    1)进行拓扑排序,如果能完成排序,则无环,否则有环;

    2)深度优先搜索算法DFS; 

     2.2 出度与入度

    出度:由一个顶点出发的边的总数;

    入度:指向一个顶点的边的总数;

    2.3 拓扑排序

    定义:就是一个有向无环图的所有定点的线性序列。

    方法:

    • 先找一个顶点,如果没有其他节点指向它;
    • 则删除该节点及其指向的边,记录该节点;
    • 重复上面两个步骤,直到所有节点都被删除掉;
    • 如果某节点存在有边指向其自己,则该图不属于有向无环图。

    3、应用:

    1)区块链技术中应用DAG技术。dag中不同节点可自己生成区块,然后选择下一个或多个区块作为子节点,可极大的加快出块速度,提高交易速度;另外,dag每个节点只存储某一时间点的交易数据,而不需要同步所有全量数据,存储更灵活,可避免无效网络消耗和数据同步造成的大量时间浪费。

    2)spark中使用DAG技术。RDD(弹性分布式数据集)是spark中最基本的计算单元,原始的RDD经过一系列转换(算子)就形成了有向无环图dag,spark根据RDD间的依赖关系分为窄依赖和宽依赖,并划分成不同的stage,spark就是通过优化和调度这些stage形成的DAG来使得计算效率最大化。

    养成好的习惯,动手写一遍,加深理解。 

    更多相关内容
  • 如果一个向图无法从某个顶点出发经过若干条边回到该点,则这个图是一个有向无环图(DAG图)。接触过算法数据结构和离散数学的,基本都知道这个东西。图论是一个专门的数学分支这里不进行讨论,DAG的应用范围非常广...

    一、有向无环图

    Directed Acyclic Graph,DAG,有向无环图。如果一个有向图无法从某个顶点出发经过若干条边回到该点,则这个图是一个有向无环图(DAG图)。接触过算法数据结构和离散数学的,基本都知道这个东西。图论是一个专门的数学分支这里不进行讨论,DAG的应用范围非常广,常见的如算法和数据结构中的最短路径问题,区块链的共识相关,包括本文要讲的任务调度问题。看一个基本的有向无环图的:

    在这里插入图片描述

    如果有对DAG感兴趣的,可以找本数学书籍看看。

    二、DAG任务分解

    任务的分解本身就是一个复杂的问题。当然,一些特定的任务不在其中。一般来说,完全把任务分解成互不依赖的可独立执行的子任务是最理想不过的,但实际情况这种现象往往是少之又少的。任务的分解,往往可以用一个类,一个函数,甚至一个代码块来做一个基本单元。分解任务不必一开始就做的很细,可以先粗略整理出一个大致的分解框架,然后再在其中不断的调整、细化。任务分解的过程,其实就是寻找任务执行的先后依赖顺序的过程,也是一个执行粒度大小的分解过程。在分解任务时,如果想去除任务循环,只要把相关的代码放到一个任务中即可。
    在任务分解完成形成DAG后,如何进行任务高度,需要有算法来支撑。对DAG来说,任务图的分层算法就是一种很好的手段。什么是图的分层呢?在有向无环图中,按顶点将其分成多层,从DAG的特点可以看出,每一层都是可以独立执行的,看一下面的图:

    在这里插入图片描述

    这种任务调试的算法的时间复杂度为O(n),n是任务图的边数。
    在DAG中,首先要明白,什么是出度什么是入度,进入顶点的有向边数量是入度,反之则为出度。在有向无环图中,一定存在一个入度为0的顶点,否则一定存在着环。那么拿到一个DAG后如何进行分层呢?
    1、首先,明确图中各个点的入度。
    2、将入度为0的顶点划成顶层或者说第一层。
    3、从第二层开始以下各层,在去除上一层顶点子图中,查找入度为0的顶点划分成一层(即去除上一层顶点的入度)。
    4、依3的方式进行循环,直至完全分解。
    通过上述分析可以看出,用图来进行任务分解,简单清晰,是一种比较好的任务并行分解方法。

    三、总结

    数学是计算机科学的基础,计算机中的许多问题都可以抽象成数学问题来解决,这也是为什么搞算法研究的很多大牛都是数学出身。学好数学,是每一个计算机程序员不得不经历的一个过程。不要说,不学数学就可以把计算机搞得很好,如果你这样说,那恰恰暴露了自身的层次。可以不研究数学,但不能不学习数学;可以不学得很深,但一定明白原理。
    基础不牢,地动山摇!

    展开全文
  • 有向无环图DAG)的实现。 该实现是快速且线程安全的。 它可以防止添加循环或重复,从而始终保持有效的DAG。 该实现缓存后代和祖先,以加快后续调用的速度。 快速开始 跑步: package main import ( "fmt" ...
  • 有向无环图DAG技术详细介绍.docx
  • 目录:1、有向无环图2、代码结构3、代码学习步鄹及方法4、重点代码讲解5、代码展现6、运行结果———————————————————————————————————1、有向无...,则这个图是一个有向无环图(DAG图)...

    目录:

    1、有向无环图

    2、代码结构

    3、代码学习步鄹及方法

    4、重点代码讲解

    5、代码展现

    6、运行结果

    ———————————————————————————————————

    1、有向无环图

    在图论中,如果一个有向图无法从某个顶点出发经过若干条边回到该点,则这个图是一个有向无环图(DAG图)。

    因为有向图中一个点经过两种路线到达另一个点未必形成环,因此有向无环图未必能转化成树,但任何有向树均为有向无环图。

    性质:有向无环图的生成树个数等于入度非零的节点的入度积。

    dcfdd881587de28752176b49a25903af.png

    2、代码结构

    f3a96194e240bd40f6bbe989a2cc10c7.png

    3、代码学习步鄹及方法

    1、本文中涉及到了Spark的Dag和设计模式中的命令

    2、Dag学习步鄹:task –> Node –> DAG –> DAGExecutor

    3、设计模式命令 http://www.voidcn.com/article/p-fxkbitkn-ov.html

    4、图解Dag类的学习步鄹

    b5830c9c2df2f89450189d0812b345c5.png

    4、重点代码讲解

    下面这段代码是核心也是最难的,如何找到父节点

    //判断Node的task节点的父节点运行状态(flase ,true)

    private def getPending: Option[T] = {

    _pending.find { name =>

    val parents = _nodes(name)

    !parents.exists(name => !_success.contains(name))

    }

    }

    1、nodes没有父节点时,!parents.exists() 为true

    2、parents.exists() 为flase时,!parents.exists() 为true

    f17705f897f33f345f419a58a13e5f7a.png

    5、代码展现

    DAG.scala

    package com.yh.dag

    import java.time.{Duration, LocalDate}

    import com.yh.nodeexecutor._

    import org.slf4j.LoggerFactory

    import scala.collection.immutable.{ListMap, ListSet}

    /** * Created by yuhui on 2016/8/25. * task --> Node --> DAG --> DAGExecutor */

    case class Node[T](task: T, parent: T*) {

    override def toString: String = {

    s"$task(${parent.mkString(",")})"

    }

    }

    case class DAG[T](nodes: Node[T]*)

    case class DAGExecutor[T](dag: DAG[T]) {

    private val LOG = LoggerFactory.getLogger(this.getClass)

    private val _nodes: Map[T, Seq[T]] = dag.nodes.map(node => (node.task, node.parent.filter(_ != null))).toMap

    private var _pending: Set[T] = ListSet()

    private var _fails = ListMap[T, String]()

    private var _success = Seq[T]()

    //判断Node的task节点的父节点运行状态(flase ,true)

    private def getPending: Option[T] = {

    _pending.find { name =>

    val parents = _nodes(name)

    !parents.exists(name => !_success.contains(name))

    }

    }

    private def fail(name: T, message: String): Unit = {

    _pending -= name

    _fails += name -> message

    for (child _nodes(child).contains(name))) {

    fail(child, s"依赖的任务无法执行: $name")

    }

    }

    private def success(name: T): Unit = {

    _pending -= name

    _success = _success :+ name

    }

    def execute(func: T => Unit): Unit = {

    _pending = _nodes.keySet

    _fails = ListMap()

    _success = Seq()

    var running = true

    while (running) {

    val taskOpt = getPending

    if (taskOpt.nonEmpty) {

    val task = taskOpt.get

    val startMills = System.currentTimeMillis()

    LOG.info("start task {}", task)

    try {

    println("=============")

    func(task) //执行executor方法

    println("+++++++++++++")

    val time = Duration.ofMillis(System.currentTimeMillis() - startMills)

    LOG.info(s"end task $task time=$time")

    success(task)

    } catch {

    case e: Throwable => fail(task, e.getMessage)

    LOG.error(e.getMessage, e)

    LOG.info(s"fail task $task")

    }

    } else {

    running = false

    }

    }

    for (name

    LOG.info(s"success task: $name")

    }

    for (name

    LOG.info(s"fail task: ${name._1} - ${name._2}")

    }

    }

    }

    object DAG {

    val allSDKDAG = new DAG[Task](

    Node(UserDetailsExecutor, WebSdkparseExecutor),

    Node(UserTagExecutor, WebSdkparseExecutor,WebSdkparseExecutor),

    Node(WebSdkparseExecutor),

    Node(UserOverviewExecutor, WebSdkparseExecutor)

    )

    def main(args: Array[String]): Unit = {

    DAGExecutor(allSDKDAG).execute { task =>task.executor("appkey": String, LocalDate.now(), LocalDate.now())}

    }

    }

    Task.scala

    package com.yh.dag

    import java.time.LocalDate

    import org.apache.spark.sql.SQLContext

    import org.slf4j.LoggerFactory

    /** * Created by yuhui on 2016/12/27. */

    abstract class Task {

    protected val LOG = LoggerFactory.getLogger(this.getClass)

    def executor(appkey: String, startDay: LocalDate, endDay: LocalDate): Unit

    def run(appkey: String, startDay: LocalDate, endDay: LocalDate): Unit = {

    executor(appkey, startDay, endDay)

    }

    }

    abstract class Executor extends Task with SQLContextAware {

    override def run(appkey: String, startDay: LocalDate, endDay: LocalDate)={}

    }

    trait SQLContextAware {

    implicit var ctx: SQLContext = _

    }

    UserDetailsExecutor.scala

    package com.yh.nodeexecutor

    import java.time.LocalDate

    import com.yh.dag.Executor

    object UserDetailsExecutor extends Executor{

    override def executor(appkey: String, startDay: LocalDate, endDay: LocalDate): Unit = {

    println("++++我的UserDetailsProcessor的执行过程++++")

    }

    }

    UserOverviewExecutor.scala

    package com.yh.nodeexecutor

    import java.time.LocalDate

    import com.yh.dag.Executor

    /** * Created by yuhui on 2016/12/27. */

    object UserOverviewExecutor extends Executor{

    override def executor(appkey: String, startDay: LocalDate, endDay: LocalDate): Unit = {

    println("++++我的UserOverviewProcessor的执行过程++++")

    }

    }

    UserTagExecutor.scala

    package com.yh.nodeexecutor

    import java.time.LocalDate

    import com.yh.dag.Executor

    /** * Created by yuhui on 2016/12/27. */

    object UserTagExecutor extends Executor{

    override def executor(appkey: String, startDay: LocalDate, endDay: LocalDate): Unit = {

    println("++++我的UserTagProcessor的执行过程++++")

    }

    }

    WebSdkparseExecutor.scala

    package com.yh.nodeexecutor

    import java.time.LocalDate

    import com.yh.dag.Executor

    /** * Created by yuhui on 2016/12/27. */

    object WebSdkparseExecutor extends Executor{

    override def executor(appkey: String, startDay: LocalDate, endDay: LocalDate): Unit = {

    println("++++我的WebSdkparseProcessor的执行过程++++")

    }

    }

    6、运行结果

    =============

    ++++我的WebSdkparseProcessor的执行过程++++

    +++++++++++++

    =============

    ++++我的UserDetailsProcessor的执行过程++++ +++++++++++++

    =============

    ++++我的UserTagProcessor的执行过程++++

    +++++++++++++

    =============

    ++++我的UserOverviewProcessor的执行过程++++ +++++++++++++

    Process finished with exit code 0

    展开全文
  • 有向无环图DAG

    2021-07-13 21:21:12
    定义:若一个不存在,则称为有向无环图(Directed Acyclic Graph) 一、描述表达式 对于这个表达式使用二叉树表示 显然红色和绿色部分冗余了 我们可以将这两个冗余部分合并,以减少存储空间 就形成了...

    目录

    一、描述表达式

    二、拓扑排序

    三、逆拓扑排序

    小结:

    下一篇:图的关键路径


    定义:若一个有向图不存在环,则称为有向无环图(Directed Acyclic Graph)

    一、描述表达式

    对于这个表达式使用二叉树表示

    显然红色和绿色部分冗余了

    我们可以将这两个冗余部分合并,以减少存储空间

    就形成了一个DAG图

    其中还有可以合并的部分

    全部合并后

     

    在考研题目中

    这种题目很容易漏掉某个可合并项

     

    比较好的方法:

     

    练习:

     

    第一步

    第二步:自底向上合并同层

     

     

     

    二、拓扑排序

    AOV网(Activity Vertex Network,用顶点表示活动的网)

    用DAG图表示一个工程,顶点表示活动,有向边<Vi,Vj>表示活动Vi必须先于Vj进行,例如

     

    拓扑排序定义:

    即找到做事的先后顺序

    上面的番茄炒蛋项目的排序

     

    实现步骤:

    步骤3中当网中不存在无前驱的顶点说明,该图有回路

    有回路则无拓扑排序

     

    代码(伪):

    /*

    基于邻接矩阵

    */

    bool TopologicalSort(Graph G){

    //初始化一个栈

    //这里可以用队列或者数组代替

    //因为只是为了存储入度为0的顶点

    InitStack(S);

    for(int i=0;i<G.vexnum;i++){

    //这里indegree数组是用来存储每个顶点的入度的

    //把当前所有入度为0的顶点入栈

    if(indegree[i]==0){

    push(S,i);

    }

    }

    int count;//用来记录有多少个顶点被排序了

    while(!IsEmpty(S)){

    Pop(S,i);

    //将栈中顶点加入打印数组print

    print[count++]=i;

    //将所有i指向顶点的入度-1,并将入度减为0的顶点入栈

    for(p=G.vertices[i].firstarc;p;p=p->nextarc){

    v=p->adjvex;//获取该边指向的顶点

    if(!(--indegree[v])){

    push(S,v);//入度为0则入栈

    }

    }

    }

    //如果计数器小于图中 结点数,说明有回路,排序失败

    if(count<G.vexnum)return false;

    else return true;

    }

     

    时间复杂度:

    O(|V|+|E|)

    若是邻接矩阵则需要O(|V|^2)

     

     

     

    三、逆拓扑排序

    就是删除每次都删除出度为0的顶点

    代码略:大概就是将indgree数组改为出度数组,没删除一个顶点都把该顶点的入度顶点-1,并判断有没有为0的就入栈

     

    时间复杂度:

    使用邻接表会很慢,每次都要遍历整个表来找入度

    可以使用逆邻接表,就是邻接表是出度作为链表,则逆邻接表就是用入度作为每个结点的链表

    使用邻接矩阵就方便点

     

    逆拓扑排序dfs实现:

    利用dfs的特性很好实现,递归到最深处退栈的时候输出

    //DFS实现逆拓扑排序

    void DFSTraverse(Graph G){

    //初始化与处理连通分量

    for(v=0;v<G.vexnum;v++){

    visited[v]=false;

    }

    for(v=0;v<G.vexnum;v++){

    if(!visited[v]){

    DFS(G,v);

    }

    }

    }

    void DFS(Graph G,int v){

    visited[v]=true;

    for(w=FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w)){

    if(!visited[w]){

    DFS(G,w);

    }        

    }

    print(v);//函数返回时(退栈)输出顶点

    }

    对于有环路,那么一定造成这种情况:某个顶点还在函数调用栈中等待回溯被打印,但是有另一个顶点的下一个邻接顶点是该顶点造成回路,我的解决办法是增加一个递归标记数组,当这个顶点被dfs调用处理的时候将其对应位置设置为1,退栈时还原为0,在处理每个顶点的下一个顶点前都判断一下:下一个顶点的标记数组是否为1即可

    类似于如下红线部分

     

     

    小结:

     

    展开全文
  • 达格 有向无环图的Golang实现总览这个包...
  • 理解有向无环图DAG

    2021-03-31 17:57:24
    In mathematics, particularly graph theory, and computer science, a directed acyclic graph (DAG) is a directed graph with no directed cycles. That is, it consists of vertices and edges, with each edge ...
  • 在这些情况下, d3-hierarchy可能无法满足您的需求,这就是为什么存在d3-dag有向无环图)的原因。 该模块实现了用于处理DAG的数据结构。 旧版本旨在尽可能地模仿d3-hierarchy的api,新版本则选择使用现代...
  • 拓扑排序原理:对有向无环图DAG的顶点进行排序,使得对于每一条向边(u,v),均u(在排序记录中)比v先出现,亦可理解为对某点v而言,只有当v的所有源点均出现了v才能出现 根据定义,可以得到以下两个结论: 如果...
  • 3.2 RDD依赖与有向无环图DAG

    千次阅读 2017-08-20 14:38:42
    有向无环图DAG):Directed Acycle graph,反应RDD之间的依赖关系; DAG每个节点代表啥?代表的一个RDD transformation: 1) 一个RDD生成两个RDD: RDD2 = RDD1.filter(xxxxx) RDD3 = RDD1.filter(yyyy) 是...
  • 1)缩点的实际作用:把一个向带环图,变成一个有向无环图DAG) ,这样基于DAG的算法就能跑了。 2)可以算缩点后个点的出度 基本思想 一我们既然能在中找到,那么我们就可以吧给缩成点了(利用...
  • 达利 Dagli是一种机器学习框架,可以轻松地用 (和其他JVM语言)编写抗错误,可读性强,高效,可维护且易于部署的模型。 这是一个文本分类器的介绍性示例,该文本分类器实现为管道,该管道使用梯度增强决策树模型...
  • Apache Spark中的有向无环图DAG

    千次阅读 2020-01-14 17:15:38
    Apache Spark中的有向无环图DAG 由DATAFLAIR TEAM·更新·2018年11月21日 1.目的 在本Apache Spark教程中,我们将了解Apache Spark中的DAGDAG Scheduler是什么,Spark中对有向无环图的需求,如何在Spark中...
  • 比较、聚合和聚类有向无环图 (DAG)。 纸张代码: Eric Malmi、Nikolaj Tatti 和 Aristides Gionis,“超越排名:比较有向无环图”。 在数据挖掘和知识发现中,2015 年。 主要文件 dag_dist.m DAG 的距离度量。 ...
  • 有向无环图DAG(代码及图解)

    千次阅读 2018-08-20 15:49:53
    在图论中,如果一个向图无法从某个顶点出发经过若干条边回到该点,则这个图是一个有向无环图(DAG图)。  因为向图中一个点经过两种路线到达另一个点未必形成,因此有向无环图未必能转化成...
  • 算法精解:DAG有向无环图

    千次阅读 2020-10-25 18:23:28
    关键字:DAG有向无环图,算法,背包,深度优先搜索,栈,BlockChain,区块链 是数据结构中最为复杂的一种,我在上大学的时候,的这一章会被老师划到考试范围之外,作为我们的课后兴趣部分。但实际上,...
  • DAG有向无环图)易懂介绍

    千次阅读 2020-06-13 08:30:49
    DAG看他的结构挺唬人的,但是原理还是蛮简单的。 一个(graph)是由两部分...所谓有向无环图其实就是:方向的边;这些边在一个中不会构成一个闭合的环路。 窥探DAG的思想,需要从他的三个基本参数来看 ...
  • 给定邻接矩阵格式的 DAG,此代码将确定节点的拓扑排序,并使用该排序有效地计算 DAG 的传递归约。 该包还包含生成随机非传递 DAG 以及派生传递 DAG 作为算法测试用例的代码。 包括将生成的 DAG 写入图形文件格式 ....
  • Spark有向无环图DAG工作原理

    千次阅读 2018-08-27 20:38:56
    At high level, when any action is called on the RDD, Spark creates the DAG and submits it to the DAG scheduler. The DAG scheduler divides operators into stages of tasks. A stage is comprised of ...
  • 有向无环图DAG)的温故知新

    千次阅读 2021-08-02 00:10:14
    无法形成拓扑序 } } } DAG 的单源最短路径 中节点的单源最短路径可以使用Dijkstra,BellmanFord, SPFA算法,而对于有向无环图DAG来说,可以通过简单的动态规划来进行求解。DAG的独特之处是所有节点可以线性化(拓扑...
  • 34 邻接矩阵:有向无环图DAG)的判断作者: 冯向阳时间限制: 1S章节: DS:截止日期: 2022-06-30 23:55:00问题描述 :目的:使用C++模板设计并逐步完善的邻接矩阵抽象数据类型(ADT)。内容:(1)请参照的邻接...
  • Laravel 基于 SQL 的有向无环图 (DAG) 解决方案 这个包允许你创建、保存和删除有向无环图。 基本用法创建直接边: $ newEdges = dag ()-> createEdge ( $ startVertex , $ endVertex , $ source );// $newEdges ...
  • 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑...
  • 具有边缘标记的简单DAG有向无环图)模块。 安装 $ npm install dagjs 用法 let Dag = require ( 'dagjs' ) ; let dag = new Dag ( ) ; // ... 例子 添加边: let dag = new Dag ( ) ; // add(from, to, tags, ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 21,572
精华内容 8,628
关键字:

有向无环图dag