成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

有向無環(huán)圖自動(dòng)布局

shenhualong / 1202人閱讀

摘要:判斷是否成環(huán)執(zhí)行拓?fù)渑判颍绻蛄兄械捻旤c(diǎn)數(shù)不等于有向圖的頂點(diǎn)個(gè)數(shù),則說明圖中存在環(huán)。如果訪問過,且不是其父節(jié)點(diǎn),那么就構(gòu)成環(huán)圖有向無環(huán)圖的最小路徑覆蓋圖存儲(chǔ)鄰接矩陣圖的鄰接矩陣存儲(chǔ)方式是用兩個(gè)數(shù)組來表示圖。

何為有向無環(huán)圖?

1、首先它是一個(gè)圖,然后它是一個(gè)有向圖,其次這個(gè)有向圖的任意一個(gè)頂點(diǎn)出發(fā)都沒有回到這個(gè)頂點(diǎn)的路徑,是為有向無環(huán)圖
2、DAG(Directed Acyclic Graph)不一定能轉(zhuǎn)化為樹,但是樹一定是一個(gè)DAG

DAG相關(guān)問題

拓?fù)湫蛄?/p>

圖中任意一對頂點(diǎn)u和v,若邊(u,v)∈E(G),則u在線性序列中出現(xiàn)在v之前。拓?fù)渑判蛑饕脕斫鉀Q有向圖中的依賴問題
求一個(gè)DAG的一條拓?fù)湫蛄校?br>1.找到當(dāng)前所有的無直接前驅(qū)的節(jié)點(diǎn)(入度為0),若沒有這樣的頂點(diǎn),跳到3。若有,從中選一個(gè)v,標(biāo)記為已訪問,加入到當(dāng)前序列的尾部,繼續(xù)2。
2.將從v出發(fā)的有向邊全部刪除(這樣會(huì)得到一個(gè)新的有向圖G’)。
3.如果序列中的頂點(diǎn)數(shù)不等于有向圖G的頂點(diǎn)個(gè)數(shù),則說明圖G中存在環(huán);如果相等,則該序列即是所求的拓?fù)湫蛄小?br>

{ 1, 2, 4, 3, 5 }

判斷是否成環(huán)

1、執(zhí)行拓?fù)渑判?,如果序列中的頂點(diǎn)數(shù)不等于有向圖G的頂點(diǎn)個(gè)數(shù),則說明圖G中存在環(huán)。
2、深度優(yōu)先遍歷該圖,如果在遍歷的過程中,發(fā)現(xiàn)某個(gè)節(jié)點(diǎn)有一條邊指向已經(jīng)訪問過的節(jié)點(diǎn),并且這個(gè)已訪問過的節(jié)點(diǎn)不是當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)(這里的父節(jié)點(diǎn)表示dfs遍歷順序中的父節(jié)點(diǎn)),則表示存在環(huán)。
換種說法:1條深度遍歷路線中如果有結(jié)點(diǎn)被第二次訪問到,那么有環(huán)。

bool dfs(int i,int pre){
    visit[i]=true;
    for(int j=1;j<=v;j++)
        if(g[i][j])
        {
            if(!visit[j])
                return dfs(j,i);
            else if(j!=pre)  //如果訪問過,且不是其父節(jié)點(diǎn),那么就構(gòu)成環(huán)
                return true;
        }
}

DAG圖(有向無環(huán)圖)的最小路徑覆蓋

圖存儲(chǔ)

鄰接矩陣

圖的鄰接矩陣(Adjacency Matrix)存儲(chǔ)方式是用兩個(gè)數(shù)組來表示圖。一個(gè)一維的數(shù)組存儲(chǔ)圖中頂點(diǎn)信息,一個(gè)二維數(shù)組(稱為鄰接矩陣)存儲(chǔ)圖中的邊或弧的信息。
設(shè)圖G有n個(gè)頂點(diǎn),則鄰接矩陣是一個(gè)n*n的方陣
無向圖:

有向圖:

鄰接表

鄰接表的核心思想就是針對每個(gè)頂點(diǎn)設(shè)置一個(gè)鄰居表。

以上面的圖為例,這是一個(gè)有向圖,分別有頂點(diǎn)a, b, c, d, e, f, g, h共8個(gè)頂點(diǎn)。使用鄰接表就是針對這8個(gè)頂點(diǎn)分別構(gòu)建鄰居表,從而構(gòu)成一個(gè)8個(gè)鄰居表組成的結(jié)構(gòu),這個(gè)結(jié)構(gòu)就是我們這個(gè)圖的表示結(jié)構(gòu)或者叫存儲(chǔ)結(jié)構(gòu)。

const node = [a, b, c, d, e, f, g, h];
const edges = [{b, c, d, e, f},  // a 的鄰居表
{c, e},  // b 的鄰居表
6a22guqa,  // c 的鄰居表
{e},  // d 的鄰居表
{f},  // e 的鄰居表
{c, g, h},  // f 的鄰居表
{f, h},  // g 的鄰居表
{f, g}]  // h 的鄰居表
圖布局

graphlib
graphlib提供表示圖的數(shù)據(jù)結(jié)構(gòu)。它不做布局或渲染
darge
dagre執(zhí)行節(jié)點(diǎn),布局節(jié)點(diǎn)位置,其中所有節(jié)點(diǎn)通過一個(gè)graphlib圖表示的布局(x和y定位)。它不會(huì)渲染。
dagre-d3
dagre-d3使用dagre進(jìn)行布局,并使用d3進(jìn)行渲染。請注意,dagre-d3默認(rèn)包含dagre和graphlib,如dagreD3.dagre和dagreD3.graphlib。
元素:

graph,即圖整體,我們可以對圖配置一些全局參數(shù)。
node,即頂點(diǎn),dagre 在計(jì)算時(shí)并不關(guān)心 node 實(shí)際的形狀、樣式,只要求提供維度信息。
edge,即邊,edge 需要聲明其兩端的 node 以及本身方向。例如A -> B表示一條由 A 指向 B 的 edge。
rank,即層級(jí),rank 是 DAG 布局中的核心邏輯單位,edge 兩端的 node 一定屬于不同的 rank,而同一 rank 中的 node 則會(huì)擁有同樣的深度坐標(biāo)(例如在縱向布局的 graph 中 y 坐標(biāo)相同)。
label,即標(biāo)簽,label 不是 DAG 中的必要元素,但 dagre 為了適用更多的場景增加了對 edge label 的布局計(jì)算。

深入理解rank:

A->B;
B->C;
    +---+       +---+        +---+  
    | A |------>| B |------->| C |  
    +---+       +---+        +---+

A B C分別處于3個(gè)rank

A->B;
A->C;
                +---+
            --> | B |
    +---+--/    +---+
    | A |
    +---+--    +---+
            --> | C |
                +---+

A 處于rank1,B C都處于A的下一層級(jí)rank2

A->B;
B->C;
A->C;
                +---+
             -->| B |---
    +---+---/   +---+    --->+---+  
    | A |                    | C |  
    +---+------------------->+---+

在這個(gè)示例中,我們發(fā)現(xiàn) edge 兩端的 node 可以相差超過一個(gè) rank。由于 edge 兩端的 node 不可屬于同樣的 rank,所以我們不能讓 B 和 C 屬于同一個(gè) rank,進(jìn)而最優(yōu)的繪制結(jié)果為 A 和 C 之間相隔兩個(gè) rank。
布局算法
DAG 可以用于模型化許多不同種類的信息,因此將一個(gè) DAG 數(shù)據(jù)結(jié)構(gòu)可視化的需求也變得非常普遍。并且由于大部分圖的數(shù)據(jù)都非常復(fù)雜甚至動(dòng)態(tài)變化,所以自動(dòng)、可配置的 DAG 可視化布局算法顯然比人為排版更為高效且可靠。
約束條件:

結(jié)點(diǎn)之間不能有重疊

連線之間盡量減少交差

結(jié)點(diǎn)之間是有基本的層次關(guān)系對齊的

主要分4個(gè)步驟:
1、消除圖中的環(huán)。
2、尋找最優(yōu)的等級(jí)(分層)分配。
3、在同一個(gè)等級(jí)內(nèi),設(shè)置頂點(diǎn)的順序,使交叉數(shù)最小。
4、計(jì)算頂點(diǎn)的坐標(biāo)。
dagre布局步驟:

removeSelfEdges // 刪除自環(huán)邊
acyclic.run // 反向設(shè)置成環(huán)的邊
rank // 計(jì)算最優(yōu)的等級(jí)分配
order // 同層排序
insertSelfEdges // 插入自環(huán)邊
position // 計(jì)算頂點(diǎn)的坐標(biāo)
acyclic.undo // 恢復(fù)反向邊設(shè)置

尋找成環(huán)的邊:

遍歷所有的節(jié)點(diǎn),遞歸遍歷每個(gè)節(jié)點(diǎn)的出邊,把一條路徑上的所有節(jié)點(diǎn)按路徑順序入棧,當(dāng)遍歷到某個(gè)出邊的目標(biāo)點(diǎn)已經(jīng)在這個(gè)路徑上遍歷過了,那么這條邊就是成環(huán)的邊,存下來,然后對所有成環(huán)邊反向。

function dfsFAS(g) {
  var fas = [];
  var stack = {};
  var visited = {};

  function dfs(v) {
    if (_.has(visited, v)) {
      return;
    }
    visited[v] = true;
    stack[v] = true;
    _.forEach(g.outEdges(v), function(e) {
      if (_.has(stack, e.w)) {
        fas.push(e);
      } else {
        dfs(e.w);
      }
    });
    delete stack[v];
  }

  _.forEach(g.nodes(), dfs);
  return fas;
}

算法:network-simplex(網(wǎng)絡(luò)單純型) longest-path(最長路徑)

ranker=network-simplex

A->B->C->E;
A->D->F;
A->G->H->I->J;

                +---+        +---+        +---+
               >| B |------->| C |------->| E |
             -/ +---+        +---+        +---+
           -/
    +---+-/     +---+        +---+
    | A |------>| D |------->| F |
    +---+-     +---+        +---+
           -
             - +---+        +---+        +---+        +---+
               >| G |------->| H |------->| I |------->| J |
                +---+        +---+        +---+        +---+
ranker=longest-path
A->B->C->E;
A->D->F;
A->G->H->I->J;
                             +---+        +---+        +---+
                         --->| B |------->| C |------->| E |
                   -----/    +---+        +---+        +---+
             -----/
    +---+---/                             +---+        +---+
    | A |-------------------------------->| D |------->| F |
    +---+-                               +---+        +---+
           -
             - +---+        +---+        +---+        +---+
               >| G |------->| H |------->| I |------->| J |
                +---+        +---+        +---+        +---+

longestPath算法就是快速初始化一個(gè)層級(jí)關(guān)系,求出來的是一條路徑的盡頭都對齊,定為0,然后逆向路徑計(jì)算,都為負(fù)值。
深度優(yōu)先遍歷

function longestPath(g) {
  var visited = {};
  // 深度優(yōu)先
  function dfs(v) {
    var label = g.node(v);
    if (_.has(visited, v)) {
      return label.rank;
    }
    visited[v] = true;
    // g.outEdges(v) v點(diǎn)的出度,v的rank就是他出度的點(diǎn)的層級(jí)減去出度的minlen,如果v是指向多個(gè)點(diǎn)的,那么就取最小的那個(gè)層級(jí)
    var rank = _.min(_.map(g.outEdges(v), function(e) {
      return dfs(e.w) - g.edge(e).minlen;
    }));

    if (rank === Number.POSITIVE_INFINITY || // return value of _.map([]) for Lodash 3
        rank === undefined || // return value of _.map([]) for Lodash 4
        rank === null) { // return value of _.map([null])
      rank = 0;
    }
    return (label.rank = rank);
  }
  _.forEach(g.sources(), dfs);
}

緊湊樹型:
1、任意節(jié)點(diǎn)的層級(jí)必須滿足邊的長度大于等于邊的minlen最小長度。
2、某條邊的松弛度被定義為其長度和最小長度之間的差值,邊的松弛度為0,則為緊湊的。

從圖中任意找一個(gè)節(jié)點(diǎn),作為起點(diǎn),從這個(gè)點(diǎn)開始遞歸找到一棵最大的緊湊樹,并返回這顆樹的節(jié)點(diǎn)個(gè)數(shù)。
遞歸遍歷松弛度為0的節(jié)點(diǎn)加到新的樹上,新樹的節(jié)點(diǎn)個(gè)數(shù)少于舊樹的節(jié)點(diǎn)個(gè)數(shù),說明還有節(jié)點(diǎn)因?yàn)樗沙诙却笥?而沒被加到新樹上。在所有的邊里找只有起點(diǎn)或者終點(diǎn)只有一個(gè)在新樹上的邊,然后判斷邊的兩個(gè)端點(diǎn)里不在新樹上的節(jié)點(diǎn)是起點(diǎn)還是終點(diǎn),如果是起點(diǎn),則把新樹上所有的點(diǎn)對應(yīng)的舊樹上的點(diǎn)的rank加這個(gè)點(diǎn)的松弛度,如果是終點(diǎn)則是減去松弛度。

function tightTree(t, g) {
  function dfs(v) {
    // 遍歷v節(jié)點(diǎn)的所有邊,然后檢查邊的對點(diǎn)是否存在樹上,不存在且該邊是緊湊的即緊湊度是0,則該點(diǎn)可以加到這棵樹上
    _.forEach(g.nodeEdges(v), function(e) {
      var edgeV = e.v,
          w = (v === edgeV) ? e.w : edgeV;
      if (!t.hasNode(w) && !slack(g, e)) {
        t.setNode(w, {});
        t.setEdge(v, w, {});
        dfs(w);
      }
    });
  }

  _.forEach(t.nodes(), dfs);
  return t.nodeCount();
}
                             +---+        +---+        +---+
                         --->| B |------->| C |------->| E |
                   -----/    +---+        +---+        +---+
             -----/            -2           -1           0
    +---+---/                             +---+        +---+
    | A |-------------------------------->| D |------->| F |
    +---+-                               +---+        +---+
     -4    -                               -1           0
             - +---+        +---+        +---+        +---+
               >| G |------->| H |------->| I |------->| J |
                +---+        +---+        +---+        +---+
                  -3           -2           -1           0
                +---+        +---+        +---+
               >| B |------->| C |------->| E |
             -/ +---+        +---+        +---+
           -/     -2           -1           0
    +---+-/                               +---+        +---+
    | A |-------------------------------->| D |------->| F |
    +---+-                               +---+        +---+
     -3    -                               -1           0
             - +---+        +---+        +---+        +---+
               >| G |------->| H |------->| I |------->| J |
                +---+        +---+        +---+        +---+
                  -2           -1           0           1
                +---+        +---+        +---+
               >| B |------->| C |------->| E |
             -/ +---+        +---+        +---+
           -/     -1           0            1
    +---+-/     +---+        +---+
    | A |------>| D |------->| F |
    +---+-     +---+        +---+
     -2    -     -1           0
             - +---+        +---+        +---+        +---+
               >| G |------->| H |------->| I |------->| J |
                +---+        +---+        +---+        +---+
                  -1           0            1            2

排序:
每層中的頂點(diǎn)順序決定了布局的邊交叉情況,因此一個(gè)好的層級(jí)內(nèi)頂點(diǎn)順序應(yīng)該要盡量少產(chǎn)生交叉邊。
前提條件:分配完層級(jí)之后,跨越多個(gè)層級(jí)的邊會(huì)被替換成由多條連接臨時(shí)節(jié)點(diǎn)或者“虛擬節(jié)點(diǎn)”的單位長度的邊。虛擬節(jié)點(diǎn)被安插到中間層級(jí)上,使得整張圖中所有邊都只連接相鄰層級(jí)的節(jié)點(diǎn)。
理論:
把多層的DAG圖,分成一個(gè)個(gè)的雙層圖,兩層兩層的進(jìn)行排序。當(dāng)訪問某一層時(shí),這一層每個(gè)頂點(diǎn)都會(huì)根據(jù)其關(guān)聯(lián)的上一層頂點(diǎn)的位置分配一個(gè)權(quán)重。然后這一層的頂點(diǎn)會(huì)根據(jù)這個(gè)權(quán)重進(jìn)行排序。
權(quán)重計(jì)算:定義一個(gè)兩層圖,下層節(jié)點(diǎn)根據(jù)上層節(jié)點(diǎn)排序,下層每個(gè)頂點(diǎn)v的權(quán)重等于:
每條與v關(guān)聯(lián)的邊的weight*order/sumWeight。weight是邊的權(quán)重,默認(rèn)為1,order是邊的上層節(jié)點(diǎn)在上層的排序,sumWeight是關(guān)聯(lián)邊的權(quán)重總和。
然后我們就可以執(zhí)行一系列迭代嘗試改進(jìn)這個(gè)順序,直到找到一個(gè)滿意的解時(shí)停止迭代。
啟發(fā)式迭代:
biasRight:重心相等時(shí)索引小的左偏還是右偏
downLayerGraphs:從上到下分層,n行根據(jù)n-1行排序
upLayerGraphs:從下到上分層,n行根據(jù)n+1行排序
重心相等時(shí)索引小的左偏的情況下,先從下到上分層掃描,排序;再進(jìn)行從上到下分層掃描,排序;
重心相等時(shí)索引小的右偏的情況下,先從下到上分層掃描,排序;再進(jìn)行從上到下分層掃描,排序;
每次排序后都會(huì)計(jì)算交叉點(diǎn)個(gè)數(shù),如果交叉?zhèn)€數(shù)更好了,則替換節(jié)點(diǎn)矩陣,然后再進(jìn)行上述的4邊掃描,直到上述4遍掃描后都沒有再取得更優(yōu)解,迭代結(jié)束。

A->B;
A->C;
A->F
B->E;
C->D;
C->G;
F->D;

原始圖:

第一次迭代:從下到上分層掃描,左偏

crossCount = 1
第二次迭代:再進(jìn)行從上到下分層掃描,左偏

crossCount = 1
第三次迭代:從下到上分層掃描,右偏

crossCount = 0
獲得了更優(yōu)解,這個(gè)迭代周期結(jié)束,重新開始一個(gè)迭代周期,在這個(gè)迭代周期都沒有再找到更優(yōu)解,迭代結(jié)束
輸出矩陣:

[
  [A],
  [25, 27, 26],
  [B, F, C],
  [28, 31, 29, 30],
  [E, D, G]
]

下面是上述過程的代碼:

function order(g) {
  var maxRank = util.maxRank(g),
      downLayerGraphs = buildLayerGraphs(g, _.range(1, maxRank + 1), "inEdges"), // 從上到下分層,n行根據(jù)n-1行排序
      upLayerGraphs = buildLayerGraphs(g, _.range(maxRank - 1, -1, -1), "outEdges"); // 從下到上分層,n行根據(jù)n+1行排序
  var layering = initOrder(g);
  assignOrder(g, layering);
  var bestCC = Number.POSITIVE_INFINITY,
      best;
  for (var i = 0, lastBest = 0; lastBest < 4; ++i, ++lastBest) {
    sweepLayerGraphs(i % 2 ? downLayerGraphs : upLayerGraphs, i % 4 >= 2); // 掃描按權(quán)重排序
    layering = util.buildLayerMatrix(g); // 節(jié)點(diǎn)id的矩陣
    var cc = crossCount(g, layering); // 返回當(dāng)前矩陣下交叉點(diǎn)個(gè)數(shù)
    if (cc < bestCC) {
      lastBest = 0;
      best = _.cloneDeep(layering);
      bestCC = cc;
    }
  }
  assignOrder(g, best);
}

計(jì)算頂點(diǎn)坐標(biāo):
節(jié)點(diǎn)的層號(hào)和層內(nèi)序號(hào)確定后,布局結(jié)果的基本框架就已經(jīng)確定了.一般有向圖可以采用在垂直方向或者水平方向按序號(hào)遞增的方式分別分配縱坐標(biāo)和橫坐標(biāo)。

實(shí)際應(yīng)用場景

1、依賴關(guān)系:
可視化項(xiàng)目依賴,組件依賴關(guān)系:比如打包編譯依賴的時(shí)候,把各種包的依賴關(guān)系按照拓?fù)湫蛄信判?,先引入排在前面的包,后引入排在后面的包?br>2、調(diào)度流程:
自動(dòng)化布局UML圖,workflow等。
事項(xiàng)流程:

spark任務(wù)執(zhí)行:大規(guī)模數(shù)據(jù)處理計(jì)算引擎

UML類圖

兒茶酚胺合成代謝路徑

3、決策樹:鄙視鏈案例-婚姻市場中的房市

4、復(fù)雜人物關(guān)系鏈分析:紅樓夢

參考資料:
http://jgaa.info/accepted/200...
http://www.jos.org.cn/jos/ch/...
http://leungwensen.github.io/...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/106039.html

相關(guān)文章

  • Graph 數(shù)據(jù)可視化:JS 自動(dòng)布局有向環(huán)圖

    摘要:可以用于模型化許多不同種類的信息,因此將一個(gè)數(shù)據(jù)結(jié)構(gòu)可視化的需求也變得非常普遍。并且由于大部分圖的數(shù)據(jù)都非常復(fù)雜甚至動(dòng)態(tài)變化,所以自動(dòng)可配置的可視化布局算法顯然比人為排版更為高效且可靠。 有向無環(huán)圖(DAG)布局 有向無環(huán)圖及其布局算法 有向無環(huán)圖(directed acyclic graph,以下簡稱 DAG)是一種常見的圖形,其具體定義為一種由有限個(gè)頂點(diǎn)和有限條帶有方向的邊組成的圖...

    zhouzhou 評(píng)論0 收藏0
  • IaC 自動(dòng)化配置與編排神器 - Terraform 深度解析

    摘要:而對于依賴關(guān)系的抽象,業(yè)界最通行的做法即使用有向無環(huán)圖,來描述事務(wù)間的依賴關(guān)系。圖表并行遍歷,執(zhí)行資源動(dòng)作從根節(jié)點(diǎn)開始,并行地去編排整個(gè)資源拓?fù)?,遍歷整個(gè)有向無環(huán)圖,直到所有資源都被成功編排,并執(zhí)行清理操作。前言Terraform 是 Hashicorp 公司開源的一種多云資源編排工具。使用者通過一種特定的配置語言(HCL Hashicorp Configuration Language)來...

    Tecode 評(píng)論0 收藏0
  • 算法(第4版) Chapter 4.2 有向

    摘要:只好特地拎出來記錄證明一下算法步驟第一步在逆圖上運(yùn)行,將頂點(diǎn)按照逆后序方式壓入棧中顯然,這個(gè)過程作用在有向無環(huán)圖上得到的就是一個(gè)拓?fù)渑判蜃饔迷诜巧系玫降氖且粋€(gè)偽拓?fù)渑判虻诙皆谠瓐D上按第一步的編號(hào)順序進(jìn)行。等價(jià)于已知在逆圖中存在有向路徑。 Algorithms Fourth EditionWritten By Robert Sedgewick & Kevin WayneTranslat...

    曹金海 評(píng)論0 收藏0
  • Spark Streaming遇到問題分析

    摘要:遇到問題分析之后搞了個(gè)還沒仔細(xì)了解可參考的與的有區(qū)別及并發(fā)控制先看看的,與的這幾個(gè)概念。一個(gè)可以認(rèn)為就是會(huì)最終輸出一個(gè)結(jié)果的一條由組織而成的計(jì)算。在中,我們通過使用新極大地增強(qiáng)對狀態(tài)流處理的支持。 Spark Streaming遇到問題分析 1、Spark2.0之后搞了個(gè)Structured Streaming 還沒仔細(xì)了解,可參考:https://github.com/lw-lin/...

    stormzhang 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<