日B视频 亚洲,啪啪啪网站一区二区,91色情精品久久,日日噜狠狠色综合久,超碰人妻少妇97在线,999青青视频,亚洲一区二卡,让本一区二区视频,日韩网站推荐

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

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

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

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

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

掃碼添加小助手

加入工程師交流群

經(jīng)常有讀者問我「圖」這種數(shù)據(jù)結(jié)構(gòu),因?yàn)槲覀児娞柺裁磾?shù)據(jù)結(jié)構(gòu)和算法都寫過了,唯獨(dú)沒有專門介紹「圖」。

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

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

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

那么,本文依然秉持我們號的風(fēng)格,只講「圖」最實(shí)用的,離我們最近的部分,讓你心里對圖有個(gè)直觀的認(rèn)識。

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

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

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

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

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

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

int id;

Vertex[] neighbors;

}

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

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

int val;

TreeNode[] children;

}

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

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

比如還是剛才那幅圖:

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

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

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

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

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

那么,為什么有這兩種存儲圖的方式呢?肯定是因?yàn)樗麄兏饔袃?yōu)劣。

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

你看鄰接矩陣?yán)锩婵罩敲炊辔恢?,肯定需要更多的存儲空間。

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

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

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

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

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

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

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

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

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

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

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

如果連接無向圖中的節(jié)點(diǎn)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)的,你從圖的某一個(gè)節(jié)點(diǎn)開始遍歷,有可能走了一圈又回到這個(gè)節(jié)點(diǎn)。

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

Graph graph;

boolean[] visited;

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

if (visited[s]) return;

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

visited[s] = true;

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

traverse(neighbor);

// 離開節(jié)點(diǎn) s

visited[s] = false;

}

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

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

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

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

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é)點(diǎn)的進(jìn)入和離開信息,而后者唯獨(dú)會少打印整棵樹根節(jié)點(diǎn)的進(jìn)入和離開信息。

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

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

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

題目實(shí)踐

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

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

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

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

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

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

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

解法很簡單,以0為起點(diǎn)遍歷圖,同時(shí)記錄遍歷過的路徑,當(dāng)遍歷到終點(diǎn)時(shí)將路徑記錄下來即可。

既然輸入的圖是無環(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é)點(diǎn) s 到路徑

path.addLast(s);

int n = graph.length;

if (s == n - 1) {

// 到達(dá)終點(diǎn)

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

path.removeLast();

return;

}

// 遞歸每個(gè)相鄰節(jié)點(diǎn)

for (int v : graph[s]) {

traverse(graph, v, path);

}

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

path.removeLast();

}

這道題就這樣解決了。

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

在筆試中,最常考的算法是圖的遍歷,和多叉樹的遍歷框架是非常類似的。

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

責(zé)任編輯:lq6

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

    關(guān)注

    23

    文章

    4810

    瀏覽量

    98619
  • 節(jié)點(diǎn)
    +關(guān)注

    關(guān)注

    0

    文章

    230

    瀏覽量

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

    關(guān)注

    3

    文章

    573

    瀏覽量

    41694

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

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

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

掃碼添加小助手

加入工程師交流群

    評論

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

    Debian 69未檢測到Intenso NVME,怎樣才能讓工作?

    嘿。我剛剛設(shè)法更新到 2.5.0 并啟動(dòng)了 Debian 版本 69。 但未檢測到我的新 NVME SSD它在閃爍,但也許我必須做其他事情然后將其內(nèi)置? 我怎樣才能讓工作? 謝謝
    發(fā)表于 03-25 06:38

    Altair OptiStruct:重構(gòu)結(jié)構(gòu)研發(fā)邏輯,引領(lǐng)工業(yè)仿真與優(yōu)化新紀(jì)元

    在工業(yè)制造向高端化、輕量化、智能化全速轉(zhuǎn)型的當(dāng)下,產(chǎn)品結(jié)構(gòu)研發(fā)早已告別“經(jīng)驗(yàn)設(shè)計(jì)+反復(fù)試制”的傳統(tǒng)模式,轉(zhuǎn)而依托精準(zhǔn)仿真與智能優(yōu)化技術(shù),實(shí)現(xiàn)性能、成本、效率的三重突破。作為Altair澳汰爾旗下歷經(jīng)
    發(fā)表于 03-20 10:25

    怎樣開始啟用獨(dú)立看門狗呢?

    看門狗的原理是什么呢? 怎樣開始啟用獨(dú)立看門狗呢?
    發(fā)表于 01-08 06:33

    深入Linux內(nèi)核:進(jìn)程調(diào)度的核心邏輯實(shí)現(xiàn)細(xì)節(jié)

    ,背后都離不開內(nèi)核調(diào)度算法的精準(zhǔn)操控。今天,我們就從優(yōu)先級、調(diào)度算法、時(shí)間片分配到底層實(shí)現(xiàn),全方位拆解Linux內(nèi)核進(jìn)程調(diào)度的核心邏輯。 一、進(jìn)程調(diào)度的“身份標(biāo)識”:優(yōu)先級與分類 要理解調(diào)度邏輯,首先得搞懂:進(jìn)程憑什么“插隊(duì)”?
    的頭像 發(fā)表于 12-24 07:05 ?4619次閱讀
    深入Linux內(nèi)核:進(jìn)程調(diào)度的核心<b class='flag-5'>邏輯</b>與<b class='flag-5'>實(shí)現(xiàn)</b>細(xì)節(jié)

    順絡(luò)繞線貼片電感結(jié)構(gòu)怎樣的?

    組成 骨架 :采用高精度材料(如陶瓷、鐵氧體或鋁)制成,作為繞線的基礎(chǔ)支撐結(jié)構(gòu)。骨架形狀多樣,包括工字型、長方形等,其中工字型骨架底部設(shè)計(jì)焊接部分,便于表面貼裝。 繞線 :使用漆包線繞制在骨架上,通過調(diào)整匝數(shù)實(shí)現(xiàn)不同電
    的頭像 發(fā)表于 11-07 17:45 ?930次閱讀
    順絡(luò)繞線貼片電感<b class='flag-5'>結(jié)構(gòu)</b>是<b class='flag-5'>怎樣</b>的?

    圖解碼說-六大UML類關(guān)系(依賴,繼承,實(shí)現(xiàn),關(guān)聯(lián),聚合,組合)

    UML 類是面向?qū)ο笤O(shè)計(jì)的 “施工”,而依賴、繼承、實(shí)現(xiàn)、關(guān)聯(lián)、聚合、組合這六大關(guān)系,就是圖中定義類與類互動(dòng)規(guī)則的核心 “語法”。掌握它們,就能快速看懂類的協(xié)作邏輯與系統(tǒng)
    的頭像 發(fā)表于 11-05 09:03 ?936次閱讀
    圖解碼說-六大UML類<b class='flag-5'>圖</b>關(guān)系(依賴,繼承,<b class='flag-5'>實(shí)現(xiàn)</b>,關(guān)聯(lián),聚合,組合)

    長晶科技邏輯芯片產(chǎn)品矩陣介紹

    邏輯IC是用于實(shí)現(xiàn)基本邏輯運(yùn)算和復(fù)合邏輯運(yùn)算的集成電路, 廣泛應(yīng)用于各種電子設(shè)備和系統(tǒng)中,成為現(xiàn)代電子設(shè)備智能化、高效化的關(guān)鍵所在。
    的頭像 發(fā)表于 11-04 17:47 ?1473次閱讀
    長晶科技<b class='flag-5'>邏輯</b>芯片產(chǎn)品矩陣介紹

    復(fù)雜的軟件算法硬件IP核的實(shí)現(xiàn)

    的函數(shù)功能的簡短的描述。 HASM 語言包含了兩種結(jié)構(gòu),一種是功能域一種是結(jié)構(gòu)域。 功能域負(fù)責(zé)一些基本的運(yùn)算操作,例如算術(shù)運(yùn)算、邏輯運(yùn)算還有數(shù)據(jù)傳送操作,通常由組合邏輯
    發(fā)表于 10-30 07:02

    AES加解密算法邏輯實(shí)現(xiàn)及其在蜂鳥E203SoC上的應(yīng)用介紹

    這次分享我們會簡要介紹AES加解密算法的邏輯實(shí)現(xiàn),以及如何將AES算法做成硬件協(xié)處理器集成在蜂鳥E203 SoC上。 AES算法介紹 AES算法屬于對稱密碼算法中的分組密碼,其明文/密文分組長度為
    發(fā)表于 10-29 07:29

    如何通過地址生成器實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò)特征的padding?

    。所以我們選擇更易實(shí)現(xiàn),更加節(jié)省控制邏輯結(jié)構(gòu)的直接存儲方式。 對于這種直接存儲方式,其填充零的判斷邏輯為: 當(dāng)目標(biāo)地址為輸出特征的第一行
    發(fā)表于 10-22 08:15

    可編程邏輯控制器PLC是什么?如何實(shí)現(xiàn)上網(wǎng)通信?

    。具有編程靈活、抗干擾強(qiáng)、適應(yīng)工業(yè)環(huán)境的特點(diǎn),廣泛應(yīng)用于制造業(yè)、交通、能源等領(lǐng)域。 PLC上網(wǎng)通信的實(shí)現(xiàn)方式 PLC實(shí)現(xiàn)上網(wǎng)通信的核心是通過通信模塊、網(wǎng)絡(luò)協(xié)議和硬件連接,將工業(yè)控制設(shè)備接入局域網(wǎng)或互聯(lián)網(wǎng),
    的頭像 發(fā)表于 09-22 17:27 ?1265次閱讀

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

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

    HarmonyOS實(shí)戰(zhàn):3秒實(shí)現(xiàn)一個(gè)自定義輪播

    輪播作為應(yīng)用程序中最普通使用的控件被廣泛應(yīng)用,相信對于來發(fā)者來說并不陌生。在 Android 中實(shí)現(xiàn)一個(gè) 輪播很多選擇使用第三方的插件,畢竟在有限的開發(fā)排期中自己動(dòng)手
    的頭像 發(fā)表于 06-24 17:06 ?1629次閱讀

    從底層邏輯到架構(gòu)設(shè)計(jì):聚徽解析MES看板的技術(shù)實(shí)現(xiàn)路徑

    與數(shù)據(jù)接口的協(xié)同設(shè)計(jì)。本文將從底層邏輯出發(fā),深入解析MES看板的技術(shù)架構(gòu)與實(shí)現(xiàn)路徑。 一、底層邏輯:數(shù)據(jù)驅(qū)動(dòng)的生產(chǎn)管理 MES看板的核心價(jià)值在于將生產(chǎn)現(xiàn)場的離散數(shù)據(jù)轉(zhuǎn)化為可執(zhí)行信息,其底層邏輯
    的頭像 發(fā)表于 06-16 15:23 ?839次閱讀

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

    由于資料內(nèi)存過大,分開上傳,有需要的朋友可以主頁搜索下載哦~ 本文以實(shí)現(xiàn)高速高可靠性的數(shù)字系統(tǒng)設(shè)計(jì)為目標(biāo),以完全同步式電路為基礎(chǔ),從技術(shù)實(shí)現(xiàn)的角度介紹ASIC邏輯電路設(shè)計(jì)技術(shù)。
    發(fā)表于 05-15 15:22
    平顶山市| 乌兰浩特市| 甘孜县| 方正县| 蒲江县| 长白| 平陆县| 闸北区| 江津市| 宣恩县| 长寿区| 崇左市| 肃宁县| 盐池县| 曲阳县| 山阴县| 大英县| 碌曲县| 凤冈县| 普兰县| 阿图什市| 孝昌县| 健康| 台山市| 新民市| 西林县| 濮阳市| 舒城县| 元阳县| 济南市| 区。| 葫芦岛市| 余庆县| 汝城县| 通渭县| 颍上县| 瓦房店市| 德钦县| 陇西县| 惠安县| 嘉荫县|