99精品伊人亚洲|最近国产中文炮友|九草在线视频支援|AV网站大全最新|美女黄片免费观看|国产精品资源视频|精彩无码视频一区|91大神在线后入|伊人终合在线播放|久草综合久久中文

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

圖的邏輯結(jié)構(gòu)是怎樣的?如何去實現(xiàn)它?

算法與數(shù)據(jù)結(jié)構(gòu) ? 來源:labuladong ? 作者:labuladong ? 2021-05-08 16:34 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

經(jīng)常有讀者問我「圖」這種數(shù)據(jù)結(jié)構(gòu),因為我們公眾號什么數(shù)據(jù)結(jié)構(gòu)和算法都寫過了,唯獨沒有專門介紹「圖」。

其實在學習數(shù)據(jù)結(jié)構(gòu)和算法的框架思維中說過,雖然圖可以玩出更多的算法,解決更復(fù)雜的問題,但本質(zhì)上圖可以認為是多叉樹的延伸。

面試筆試很少出現(xiàn)圖相關(guān)的問題,就算有,大多也是簡單的遍歷問題,基本上可以完全照搬多叉樹的遍歷。

至于最小生成樹,Dijkstra,網(wǎng)絡(luò)流這些算法問題,他們當然很牛逼,但是,就算法筆試來說,學習的成本高但收益低,沒什么性價比,不如多刷幾道動態(tài)規(guī)劃,真的。

那么,本文依然秉持我們號的風格,只講「圖」最實用的,離我們最近的部分,讓你心里對圖有個直觀的認識。

圖的邏輯結(jié)構(gòu)和具體實現(xiàn)

一幅圖是由節(jié)點和邊構(gòu)成的,邏輯結(jié)構(gòu)如下:

圖的邏輯結(jié)構(gòu)是怎樣的?如何去實現(xiàn)它?

什么叫「邏輯結(jié)構(gòu)」?就是說為了方便研究,我們把圖抽象成這個樣子。

根據(jù)這個邏輯結(jié)構(gòu),我們可以認為每個節(jié)點的實現(xiàn)如下:

/* 圖節(jié)點的邏輯結(jié)構(gòu) */class Vertex {

int id;

Vertex[] neighbors;

}

看到這個實現(xiàn),你有沒有很熟悉?它和我們之前說的多叉樹節(jié)點幾乎完全一樣:

/* 基本的 N 叉樹節(jié)點 */class TreeNode {

int val;

TreeNode[] children;

}

所以說,圖真的沒啥高深的,就是高級點的多叉樹而已。

不過呢,上面的這種實現(xiàn)是「邏輯上的」,實際上我們很少用這個Vertex類實現(xiàn)圖,而是用常說的鄰接表和鄰接矩陣來實現(xiàn)。

比如還是剛才那幅圖:

圖的邏輯結(jié)構(gòu)是怎樣的?如何去實現(xiàn)它?

用鄰接表和鄰接矩陣的存儲方式如下:

鄰接表很直觀,我把每個節(jié)點x的鄰居都存到一個列表里,然后把x和這個列表關(guān)聯(lián)起來,這樣就可以通過一個節(jié)點x找到它的所有相鄰節(jié)點。

鄰接矩陣則是一個二維布爾數(shù)組,我們權(quán)且成為matrix,如果節(jié)點x和y是相連的,那么就把matrix[x][y]設(shè)為true。如果想找節(jié)點x的鄰居,去掃一圈matrix[x][。。]就行了。

圖的邏輯結(jié)構(gòu)是怎樣的?如何去實現(xiàn)它?

那么,為什么有這兩種存儲圖的方式呢?肯定是因為他們各有優(yōu)劣。

對于鄰接表,好處是占用的空間少。

你看鄰接矩陣里面空著那么多位置,肯定需要更多的存儲空間。

但是,鄰接表無法快速判斷兩個節(jié)點是否相鄰。

比如說我想判斷節(jié)點1是否和節(jié)點3相鄰,我要去鄰接表里1對應(yīng)的鄰居列表里查找3是否存在。但對于鄰接矩陣就簡單了,只要看看matrix[1][3]就知道了,效率高。

所以說,使用哪一種方式實現(xiàn)圖,要看具體情況。

好了,對于「圖」這種數(shù)據(jù)結(jié)構(gòu),能看懂上面這些就綽綽夠用了。

那你可能會問,我們這個圖的模型僅僅是「有向無權(quán)圖」,不是還有什么加權(quán)圖,無向圖,等等……

其實,這些更復(fù)雜的模型都是基于這個最簡單的圖衍生出來的。

有向加權(quán)圖怎么實現(xiàn)?很簡單呀:

如果是鄰接表,我們不僅僅存儲某個節(jié)點x的所有鄰居節(jié)點,還存儲x到每個鄰居的權(quán)重,不就實現(xiàn)加權(quán)有向圖了嗎?

如果是鄰接矩陣,matrix[x][y]不再是布爾值,而是一個 int 值,0 表示沒有連接,其他值表示權(quán)重,不就變成加權(quán)有向圖了嗎?

無向圖怎么實現(xiàn)?也很簡單,所謂的「無向」,是不是等同于「雙向」?

圖的邏輯結(jié)構(gòu)是怎樣的?如何去實現(xiàn)它?

如果連接無向圖中的節(jié)點x和y,把matrix[x][y]和matrix[y][x]都變成true不就行了;鄰接表也是類似的操作。

把上面的技巧合起來,就變成了無向加權(quán)圖……

好了,關(guān)于圖的基本介紹就到這里,現(xiàn)在不管來什么亂七八糟的圖,你心里應(yīng)該都有底了。

下面來看看所有數(shù)據(jù)結(jié)構(gòu)都逃不過的問題:遍歷。

圖的遍歷

圖怎么遍歷?還是那句話,參考多叉樹,多叉樹的遍歷框架如下:

/* 多叉樹遍歷框架 */void traverse(TreeNode root) {

if (root == null) return;

for (TreeNode child : root.children)

traverse(child);

}

圖和多叉樹最大的區(qū)別是,圖是可能包含環(huán)的,你從圖的某一個節(jié)點開始遍歷,有可能走了一圈又回到這個節(jié)點。

所以,如果圖包含環(huán),遍歷框架就要一個visited數(shù)組進行輔助:

Graph graph;

boolean[] visited;

/* 圖遍歷框架 */void traverse(Graph graph, int s) {

if (visited[s]) return;

// 經(jīng)過節(jié)點 s

visited[s] = true;

for (TreeNode neighbor : graph.neighbors(s))

traverse(neighbor);

// 離開節(jié)點 s

visited[s] = false;

}

好吧,看到這個框架,你是不是又想到了 回溯算法核心套路 中的回溯算法框架?

這個visited數(shù)組的操作很像回溯算法做「做選擇」和「撤銷選擇」,區(qū)別在于位置,回溯算法的「做選擇」和「撤銷選擇」在 for 循環(huán)里面,而對visited數(shù)組的操作在 for 循環(huán)外面。

在 for 循環(huán)里面和外面唯一的區(qū)別就是對根節(jié)點的處理。

比如下面兩種多叉樹的遍歷:

void traverse(TreeNode root) {

if (root == null) return;

System.out.println(“enter: ” + root.val);

for (TreeNode child : root.children) {

traverse(child);

}

System.out.println(“l(fā)eave: ” + root.val);

}

void traverse(TreeNode root) {

if (root == null) return;

for (TreeNode child : root.children) {

System.out.println(“enter: ” + child.val);

traverse(child);

System.out.println(“l(fā)eave: ” + child.val);

}

}

前者會正確打印所有節(jié)點的進入和離開信息,而后者唯獨會少打印整棵樹根節(jié)點的進入和離開信息。

為什么回溯算法框架會用后者?因為回溯算法關(guān)注的不是節(jié)點,而是樹枝,不信你看 回溯算法核心套路 里面的圖,它可以忽略根節(jié)點。

顯然,對于這里「圖」的遍歷,我們應(yīng)該把visited的操作放到 for 循環(huán)外面,否則會漏掉起始點的遍歷。

當然,當有向圖含有環(huán)的時候才需要visited數(shù)組輔助,如果不含環(huán),連visited數(shù)組都省了,基本就是多叉樹的遍歷。

題目實踐

下面我們來看力扣第 797 題「所有可能路徑」,函數(shù)簽名如下:

List《List《Integer》》 allPathsSourceTarget(int[][] graph);

題目輸入一幅有向無環(huán)圖,這個圖包含n個節(jié)點,標號為0, 1, 2,。。。, n - 1,請你計算所有從節(jié)點0到節(jié)點n - 1的路徑。

輸入的這個graph其實就是「鄰接表」表示的一幅圖,graph[i]存儲這節(jié)點i的所有鄰居節(jié)點。

比如輸入graph = [[1,2],[3],[3],[]],就代表下面這幅圖:

圖的邏輯結(jié)構(gòu)是怎樣的?如何去實現(xiàn)它?

算法應(yīng)該返回[[0,1,3],[0,2,3]],即0到3的所有路徑。

解法很簡單,以0為起點遍歷圖,同時記錄遍歷過的路徑,當遍歷到終點時將路徑記錄下來即可。

既然輸入的圖是無環(huán)的,我們就不需要visited數(shù)組輔助了,直接套用圖的遍歷框架:

// 記錄所有路徑

List《List《Integer》》 res = new LinkedList《》();

public List《List《Integer》》 allPathsSourceTarget(int[][] graph) {

LinkedList《Integer》 path = new LinkedList《》();

traverse(graph, 0, path);

return res;

}

/* 圖的遍歷框架 */void traverse(int[][] graph, int s, LinkedList《Integer》 path) {

// 添加節(jié)點 s 到路徑

path.addLast(s);

int n = graph.length;

if (s == n - 1) {

// 到達終點

res.add(new LinkedList《》(path));

path.removeLast();

return;

}

// 遞歸每個相鄰節(jié)點

for (int v : graph[s]) {

traverse(graph, v, path);

}

// 從路徑移出節(jié)點 s

path.removeLast();

}

這道題就這樣解決了。

最后總結(jié)一下,圖的存儲方式主要有鄰接表和鄰接矩陣,無論什么花里胡哨的圖,都可以用這兩種方式存儲。

在筆試中,最??嫉乃惴ㄊ菆D的遍歷,和多叉樹的遍歷框架是非常類似的。

當然,圖還會有很多其他的有趣算法,比如二分圖判定呀,環(huán)檢測呀(編譯器循環(huán)引用檢測就是類似的算法)等等,以后有機會再講吧,本文就到這了。

責任編輯:lq6

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 算法
    +關(guān)注

    關(guān)注

    23

    文章

    4711

    瀏覽量

    95439
  • 節(jié)點
    +關(guān)注

    關(guān)注

    0

    文章

    222

    瀏覽量

    24989
  • 數(shù)據(jù)結(jié)構(gòu)

    關(guān)注

    3

    文章

    573

    瀏覽量

    40759

原文標題:為什么我沒寫過「圖」相關(guān)的算法?

文章出處:【微信號:TheAlgorithm,微信公眾號:算法與數(shù)據(jù)結(jié)構(gòu)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    光纖光譜儀是什么?一分鐘讀懂的原理與結(jié)構(gòu)

    眾多領(lǐng)域。那么,什么是光纖光譜儀?的工作原理和內(nèi)部結(jié)構(gòu)又是怎樣的?本文將用通俗易懂的方式為你揭開光纖光譜儀的“神秘面紗”。 一、什么是光纖光譜儀? 光纖光譜儀是一種通過光纖采集被測光源,并對其進行光譜分解與分析
    的頭像 發(fā)表于 07-07 14:27 ?163次閱讀

    實用電子電路設(shè)計(全6本)——數(shù)字邏輯電路的ASIC設(shè)計

    由于資料內(nèi)存過大,分開上傳,有需要的朋友可以主頁搜索下載哦~ 本文以實現(xiàn)高速高可靠性的數(shù)字系統(tǒng)設(shè)計為目標,以完全同步式電路為基礎(chǔ),從技術(shù)實現(xiàn)的角度介紹ASIC邏輯電路設(shè)計技術(shù)。
    發(fā)表于 05-15 15:22

    SMA 接頭與 PCB 原理連接的底層邏輯

    SMA插頭與PCB原理連接的底層邏輯涵蓋連接結(jié)構(gòu)、信號傳輸和電磁兼容性等多個方面。德索精密工業(yè)憑借深厚的技術(shù)積累和豐富的實踐經(jīng)驗,為電子工程師在設(shè)計和制造過程中提供有力的技術(shù)支持,助力確保信號的穩(wěn)定傳輸,提升電子設(shè)備的性能。
    的頭像 發(fā)表于 04-23 08:53 ?421次閱讀
    SMA 接頭與 PCB 原理<b class='flag-5'>圖</b>連接的底層<b class='flag-5'>邏輯</b>

    解密邏輯單元與CoreScore得分的關(guān)系

    FPGA 通過查找表 (LUT) 實現(xiàn)邏輯功能。這些 LUT 類似于真值表或卡諾 (Karnaugh map),F(xiàn)PGA 可以通過組合多個 LUT ,來實現(xiàn)幾乎任何你所需的
    的頭像 發(fā)表于 02-06 15:06 ?410次閱讀
    解密<b class='flag-5'>邏輯</b>單元與CoreScore得分的關(guān)系

    編碼器邏輯功能解析與實現(xiàn)

    在現(xiàn)代電子技術(shù)與自動化控制系統(tǒng)中,編碼器作為一種關(guān)鍵性傳感器,扮演著舉足輕重的角色。通過將機械位移或旋轉(zhuǎn)轉(zhuǎn)換成數(shù)字信號,為各種設(shè)備提供了精確的位置、速度和方向信息。本文將深入探討編碼器的邏輯功能,并解析其在實際應(yīng)用中的實現(xiàn)方式
    的頭像 發(fā)表于 11-30 14:35 ?1163次閱讀

    ads7952在一個job里面發(fā)送多條channel指令給ads,ads的通信特點是否能夠支持,其工作邏輯怎樣的?

    ads7952在autosar架構(gòu)下用spi異步通訊,dma存取數(shù)據(jù)。 在一個job里面發(fā)送多條channel指令給ads,ads的通信特點是否能夠支持,其工作邏輯怎樣的。 或者是否有其他類似的實現(xiàn)方案。
    發(fā)表于 11-29 06:51

    開發(fā)板上實現(xiàn)http協(xié)議

    VisionBoard的OpenMV固件支持了兩種HTTP協(xié)議傳方式:STA模式:VisionBoard作為站點連接無線網(wǎng)絡(luò);AP模式:VisionBoard作為無線網(wǎng)絡(luò)的創(chuàng)建者,是網(wǎng)絡(luò)的中心節(jié)點,其他設(shè)備連接
    的頭像 發(fā)表于 09-25 08:06 ?639次閱讀
    開發(fā)板上<b class='flag-5'>實現(xiàn)</b>http協(xié)議<b class='flag-5'>圖</b>傳

    利用邏輯實現(xiàn)最佳太陽能逆變器功率級設(shè)計

    電子發(fā)燒友網(wǎng)站提供《利用邏輯實現(xiàn)最佳太陽能逆變器功率級設(shè)計.pdf》資料免費下載
    發(fā)表于 09-21 11:04 ?0次下載
    利用<b class='flag-5'>邏輯</b><b class='flag-5'>實現(xiàn)</b>最佳太陽能逆變器功率級設(shè)計

    耦電容的擺放位置和作用

    。 耦電容的作用 減少電源噪聲 :耦電容能夠吸收電路中的高頻噪聲,減少電源線上的波動,從而提高電路的穩(wěn)定性。 提供瞬態(tài)電流 :在電路中,某些元件(如數(shù)字邏輯門)可能會在短時間內(nèi)需要較大的電流。
    的頭像 發(fā)表于 09-19 10:54 ?1471次閱讀

    LMH7322怎樣改善輸出波形呢 ?

    圖一 我按照LMH7322資料中,按照上圖一 畫的 PCB (見圖二) 圖二 測試時輸出的波形為: 請問工程師 怎樣改善輸出波形呢 ?
    發(fā)表于 09-02 06:57

    時序邏輯電路的描述方法有哪些

    時序邏輯電路是數(shù)字電路中的一種重要類型,具有存儲功能,能夠根據(jù)輸入信號和內(nèi)部狀態(tài)的變化來改變其輸出。時序邏輯電路廣泛應(yīng)用于計算機、通信、控制等領(lǐng)域。本文將介紹時序邏輯電路的描述方法,
    的頭像 發(fā)表于 08-28 11:37 ?1431次閱讀

    時序邏輯電路有哪些結(jié)構(gòu)特點呢

    時序邏輯電路是數(shù)字電路中的一種重要類型,具有存儲和處理信息的能力。時序邏輯電路的結(jié)構(gòu)特點主要包括以下幾個方面: 存儲元件 時序邏輯電路中最
    的頭像 發(fā)表于 08-28 11:07 ?1010次閱讀

    數(shù)字邏輯怎么把邏輯圖畫成電路

    將數(shù)字邏輯中的邏輯圖畫成電路是一個涉及多個步驟的過程,以下是一個詳細的指導(dǎo): 一、理解邏輯圖 首先,需要深入理解邏輯圖所表達的
    的頭像 發(fā)表于 08-21 17:36 ?2008次閱讀

    組合邏輯電路的結(jié)構(gòu)特點是什么?

    組合邏輯電路是一種基本的數(shù)字電路,邏輯門組成,用于實現(xiàn)各種邏輯功能。組合邏輯電路的
    的頭像 發(fā)表于 08-11 11:14 ?1846次閱讀

    邏輯電路與時序邏輯電路的區(qū)別

    的信號。理解它們之間的區(qū)別對于設(shè)計和實現(xiàn)復(fù)雜的數(shù)字系統(tǒng)至關(guān)重要。 第一部分:邏輯電路 1.1 定義 邏輯電路是一種電子電路,根據(jù)輸入信號的邏輯
    的頭像 發(fā)表于 07-30 15:00 ?1619次閱讀