【數據結構】圖論存儲結構深度解析:鄰接多重表如何實現無向圖O(1)刪邊?鄰接矩陣/鏈表/十字鏈對比

鄰接多重表

  • 導讀
  • 一、有向圖的存儲結構
  • 二、鄰接多重表
  • 三、存儲結構
  • 四、算法評價
    • 4.1 時間復雜度
    • 4.2 空間復雜度
  • 五、四種存儲方式的總結
    • 5.1 空間復雜度
    • 5.2 找相鄰邊
    • 5.3 刪除邊或結點
    • 5.4 適用于
    • 5.5 表示方式
  • 六、圖的基本操作
  • 結語

鄰接多重表

導讀

大家好,很高興又和大家見面啦!!!

經過前面的內容,我們已經學習了圖的三種存儲結構:

  • 鄰接矩陣
  • 鄰接表
  • 十字鏈表

在今天的內容中我們將會介紹圖的第四種存儲結構以及圖的一些基本操作。下面我們直接進入今天的內容;

一、有向圖的存儲結構

在有向圖中,我們可以通過3種存儲結構來存儲有向圖的頂點與弧的信息,并且這三種存儲結構各有其優缺點:

  • 鄰接矩陣
    • 優點:能高效查找兩個頂點之間的邊,適合存儲稠密圖
    • 不足:會浪費大量的存儲空間
  • 鄰接表
    • 優點:通過鏈式存儲大大節省了存儲空間,適合存儲稀疏圖
    • 不足:邊的查找效率低下
  • 十字鏈表
    • 優點:提高了弧的查找效率,節省了存儲空間
    • 不足:十字鏈表只能存儲有向圖

相較于鄰接矩陣與鄰接表,十字鏈表不僅提高了弧的查找效率,還節省了存儲空間。

但是十字鏈表法并不能像鄰接矩陣和鄰接表一樣不僅可以存儲有向圖,還可以存儲無向圖,十字鏈表法只能夠存儲有向圖。

那對于無向圖而言,有沒有一種存儲結構既能夠提高邊的查找效率,又能夠節省存儲空間呢?

二、鄰接多重表

在鄰接表中,容易求得頂點和邊的各種信息,但求兩個頂點之間是否存在邊兒執行刪除邊等操作時,需要分別在兩個頂點的邊表中遍歷,效率低。

鄰接多重表(Adjacency Multilist??)是無向圖的一種鏈式存儲結構。與十字鏈表類似,在鄰接多重表中,每條邊用一個結點表示,其結構如下所示:

ivex
ilink
jvex
jlink
info

其中:

  • ivexjvex中存儲的是該邊依附的兩個頂點編號;
  • ilink 指向的時依附于頂點 i 的下一條邊
  • jlink 指向的時依附于頂點 j 的下一條邊
  • info 中存放的時該邊的相關信息,如邊的權值

每個頂點也用一個結點表示,它由兩個域組成:

  • data 域存放該頂點的相關信息
  • firstedge 域指向的時依附于該頂點的第一條邊

鄰接多重表
在鄰接多重表中,所有依附于同一頂點的邊串聯在同一鏈表中,因為每條邊依附于兩個頂點,所以每個邊結點同時鏈接在兩個鏈表中。

在無向圖中,其鄰接表與鄰接多重表的差別在于——同一條邊在兩個表中的結點數量不同:

  • 鄰接表中,同一條邊用兩個結點表示
  • 鄰接多重表中,只用一個結點表示

三、存儲結構

鄰接多重表的存儲結構中,同樣需要定義兩種結點類型:

#define MAXSIZE 5
typedef int Edge_ElemType;				// 邊信息數據類型
typedef int Vert_ElemType;				// 頂點信息數據類型
typedef struct Edge_Node {int ivex;							// 頂點i的編號int jvex;							// 頂點j的編號struct Edge_Node* ilink, * jlink;	// 依附于頂點i與頂點j的邊Edge_ElemType info;					// 邊的信息
}ENode;									// 邊結點
typedef struct VertexNode {Vert_ElemType data;					// 頂點信息ENode* firstedge;					// 依附于頂點的第一條邊的結點
}VNode;									// 頂點結點
typedef struct Adjacency_Multilist?? {VNode vert_list[MAXSIZE];			// 頂點表int edge_num;						// 邊的數量int vert_num;						// 頂點數量
}AMGraph;								// 鄰接多重表

當圖中的邊沒有權值時,可以省略邊結點中的info域;

四、算法評價

鄰接多重表的算法評價同樣以鄰接多重表的遍歷進行評價;

4.1 時間復雜度

在鄰接多重表中,遍歷所有頂點就是遍歷一個順序表,對于頂點數為 ∣ V ∣ |V| V 的圖,其時間復雜度為 O ( ∣ V ∣ ) O(|V|) O(V)

遍歷所有邊只需要將每一條邊都遍歷一次,對于邊數為 ∣ E ∣ |E| E 的圖,其時間復雜度為 ∣ E ∣ |E| E

整個圖的遍歷對應的時間復雜度為 T ( N ) = O ( ∣ V ∣ + ∣ E ∣ ) T(N) = O(|V| + |E|) T(N)=O(V+E)

4.2 空間復雜度

在鄰接多重表中,對于頂點數為 ∣ V ∣ |V| V ,邊數為 ∣ E ∣ |E| E 的圖而言,其需要的空間復雜度為 T ( N ) = O ( ∣ V ∣ + ∣ E ∣ ) T(N) = O(|V| + |E|) T(N)=O(V+E)

五、四種存儲方式的總結

下面我們會從五個維度來探討這四種存儲方式:

5.1 空間復雜度

在鄰接矩陣中,對于結點數為 n n n 的圖,不管是有向圖還是無向圖都需要申請 n 2 n^2 n2 的空間,因此其空間復雜度均為 n 2 n^2 n2

在鄰接表中,對于結點數為 ∣ V ∣ |V| V 和邊數為 ∣ E ∣ |E| E 的圖,在有向圖和無向圖中,其空間復雜度并不相同:

  • 有向圖中,需要申請 ∣ V ∣ |V| V 個結點空間和 ∣ E ∣ |E| E 個邊空間,因此對應的空間復雜度為: O ( ∣ V ∣ + ∣ E ∣ ) O(|V| + |E|) O(V+E)
  • 無向圖中,需要申請 ∣ V ∣ |V| V 個結點空間和 2 ? ∣ E ∣ 2 * |E| 2?E 個邊空間,因此對應的空間復雜度為: O ( ∣ V ∣ + 2 ∣ E ∣ ) O(|V| + 2|E|) O(V+2∣E)

在十字鏈表中,對于結點數為 ∣ V ∣ |V| V 和邊數為 ∣ E ∣ |E| E 的圖,需要申請同等數量的結點空間和邊空間,其對應的空間復雜度為: O ( ∣ V ∣ + ∣ E ∣ ) O(|V| + |E|) O(V+E)

在鄰接多重表中,對于結點數為 ∣ V ∣ |V| V 和邊數為 ∣ E ∣ |E| E 的圖,需要申請同等數量的結點空間和邊空間,其對應的空間復雜度為: O ( ∣ V ∣ + ∣ E ∣ ) O(|V| + |E|) O(V+E)

5.2 找相鄰邊

在鄰接矩陣中,當我們要查找一個頂點的相鄰邊時,我們只需要遍歷該頂點對應的行或者列。在鄰接矩陣中,行數與列數都是圖的頂點數 ∣ V ∣ |V| V ,因此對應的時間復雜度為 O ( ∣ V ∣ ) O(|V|) O(V)

在鄰接表中,當我們要查找一個頂點的相鄰邊時,對于有向圖與無向圖而言,其查找鄰邊的時間復雜度也是有所區別:

  • 無向圖中,鄰接表查找鄰邊時,只需要遍歷該結點所指向的邊表即可
  • 有向圖中,鄰接表查找鄰邊時,對于出度與入度的時間復雜度也是有區別:
    • 出度:查找一個頂點的出度,只需要遍歷該結點所指向的邊表即可
    • 入度:查找一個頂點的入度,需要遍歷整個鄰接表

在十字鏈表中,當我們要查找一個頂點的相鄰邊時,就是查找該頂點的出度與入度,這時只需要分別遍歷該結點的出度表與入度表即可

在鄰接多重表中,當我們要查找一個頂點的相鄰邊時,只需要遍歷對應的結點所鄰接的邊表即可

5.3 刪除邊或結點

在鄰接矩陣中:

  • 當我們要刪除一條邊時,只需要修改對應邊在矩陣中的值即可
  • 當我們要刪除一個頂點時,需要移動大量的數據

在鄰接表中:

  • 有向圖:
    • 刪除邊:只需要刪除對應的邊結點即可
    • 刪除頂點:需要刪除與該結點相鄰的所有邊結點以及該頂點
  • 無向圖:
    • 刪除邊:需要刪除其依附的兩個頂點所對應的邊表中的邊結點
    • 刪除頂點:需要刪除與該結點相鄰的所有邊結點以及該頂點

在十字鏈表和鄰接多重表中:

  • 刪除邊:我們只需要刪除其對應的邊結點即可
  • 刪除頂點:需要刪除與該頂點相鄰的所有邊結點以及該頂點信息

不難發現,在圖中,當我們要刪除一個頂點時,實際上就是需要查找該頂點相鄰邊并進行刪除,因此其刪除操作是基于查找操作實現;

5.4 適用于

鄰接矩陣由于需要消耗大量的空間用于存儲邊,因此適用于存儲稠密圖;

在鄰接表中,由于邊表是通過鏈表實現,能夠節省存儲空間,因此對于稀疏圖而言,更加適合用鄰接表進行存儲;

在十字鏈表中,只能夠存儲有向圖

在鄰接多重表中,只能夠存儲無向圖

5.5 表示方式

鄰接矩陣是由各個頂點組成的矩陣,因此,其表示方式是唯一的;

在鄰接表、十字鏈表以及鄰接多重表中,由于邊表的信息是通過鏈表進行的存儲,因此其邊表的表示方式并不唯一;

六、圖的基本操作

圖的基本操作時獨立于圖的存儲結構的。而對于不同的存儲方式,操作算法的具體實現會有著不同的性能。在設計具體算法的實現時,應考慮采用何種存儲方式的算法效率會更高。

圖的基本操作主要包括:

  • Adjacent(G, x, y): 判斷圖G是否存在邊<x, y>(x, y)
  • Neighbors(G, x): 列出圖G中與結點x鄰接的邊
  • InsertVertex(G, x): 在圖G中插入頂點x
  • DeleteVertex(G, x): 在圖G中刪除頂點x
  • AddEdge(G, x, y): 若無向邊(x, y)或有向邊<x, y>不存在,則向圖G中添加改邊
  • RemoveEdge(G, x, y): 若無向邊(x, y)或有向邊<x, y>存在,則從圖G中刪除該邊
  • FirstNeighbors(G, x): 求圖G中頂點x的第一個鄰接點,若有則返回頂點號。若x沒有鄰接點或圖中不存在x,則返回-1
  • NextNeighbors(G, x, y): 假設圖G中頂點 y 是頂點 x 的一個鄰接點,返回除 y 外頂點 x 的下一個鄰接點的頂點號,若 y 是 x 的最后一個鄰接點,則返回-1
  • Get_edge_value(G, x, y): 獲取圖G中邊(x, y)<x, y> 對應的權值
  • Set_edge_value(G, x, y, v): 設置圖G中邊(x, y)<x, y> 對應的權值

此外,還有圖的遍歷算法:按照某種方式訪問圖中的每個頂點,且僅訪問一次。圖的遍歷算法有兩種:

  • 深度優先遍歷(Depth-First-Search, DFS)
  • 廣度優先遍歷(Breadth-First-Search, BFS)

具體內容會在下一個篇章中進行介紹。

結語

鄰接多重表以“單邊雙鏈”的革新設計,將無向圖的存儲效率推向新高度——空間占用減半、刪邊操作躍升至??O(1)??,完美解決了鄰接表的冗余與低效痛點。

從鄰接矩陣的剛性布局到鏈式結構的動態靈動,每一種存儲方案都是空間與時間的精妙權衡,而??鄰接多重表無疑是高頻刪邊場景的無向圖終極答案??。

??但存儲結構只是圖算法的起點??,真正的挑戰在于如何基于這些結構實現高效操作。??下一篇將深入圖的廣度優先遍歷(BFS)??,解析其在鄰接矩陣、鄰接表及鄰接多重表中的性能差異,并揭秘如何通過存儲優化讓BFS在千萬級節點圖中依然游刃有余!

🔍 ??本文是否為你撥開了圖存儲的迷霧???
👍 ??點贊??支持原創深度干貨,讓技術洞察傳播更遠!
📁 ??收藏??構建你的圖論知識庫,開發實戰隨時查閱。
🔄 ??轉發??至技術社區,與同行探討存儲選型與算法優化。
💬 評論區??留下你的疑問??:你在BFS實現中遇到過哪些性能瓶頸?我們共同拆解!
🔔 ??關注追蹤更新??,《圖的廣度優先遍歷:從理論到超大規模實戰》即將上線!

🚀 ??技術進階之路,我們并肩前行!?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/78897.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/78897.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/78897.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Rust】所有權

目錄 所有權基本概念所有權介紹棧與堆變量作用域 字符串字符串字面值&#xff08;&str&#xff09;String 類型相互轉換所有權 內存結構對比注意事項和常見坑使用場景 內存與分配變量與數據交互的方式&#xff08;一&#xff09;&#xff1a;移動變量與數據交互的方式&…

4月29日日記

終于是考完解析幾何了&#xff0c;今天昨天突擊了一下&#xff0c;感覺確實學會了很多之前不會的東西&#xff0c;但是可能距離高分還差很多。這次考試不太理想。大部分原因是前期沒學&#xff0c;吸取教訓&#xff0c;早點開始復習微積分。明天還有一節微積分&#xff0c;但是…

【深度對比】Google Play與IOS 馬甲包處理差異分析

在移動應用發布與推廣過程中&#xff0c;馬甲包&#xff08;Cloned App / Alternate Version&#xff09; 曾被廣泛用于流量測試、風險隔離、多品牌運營等場景中。隨著 Google Play 與 Apple App Store 審核政策不斷收緊&#xff0c;開發者們越來越關注兩個平臺對“馬甲包”的態…

MCP 架構全解析:Host、Client 與 Server 的協同機制

目錄 &#x1f3d7;? MCP 架構全解析&#xff1a;Host、Client 與 Server 的協同機制 &#x1f4cc; 引言 &#x1f9e9; 核心架構組件 1. Host&#xff08;主機&#xff09; 2. Client&#xff08;客戶端&#xff09; 3. Server&#xff08;服務器&#xff09; &#…

記錄一次無界微前端的簡單使用

記錄一次無界微前端使用 無界微前端主應用子應用nginx配置 無界微前端 https://wujie-micro.github.io/doc/ 因為使用的是vue項目主應用和次應用都是 所以用的封裝的。 https://wujie-micro.github.io/doc/pack/ 主應用 安裝 選擇對應的版本 # vue2 框架 npm i wujie-vue2…

LLM應用于自動駕駛方向相關論文整理(大模型在自動駕駛方向的相關研究)

1、《HILM-D: Towards High-Resolution Understanding in Multimodal Large Language Models for Autonomous Driving》 2023年9月發表的大模型做自動駕駛的論文&#xff0c;來自香港科技大學和人華為諾亞實驗室&#xff08;代碼開源&#xff09;。 論文簡介&#xff1a; 本文…

FTP-網絡文件服務器

部署思路 單純上傳下載ftp系統集成間的共享 samba網絡存儲服務器 NFS 網絡文件服務器&#xff1a;通過網絡共享文件或文件夾&#xff0c;實現數據共享 NAS &#xff08; network append storage):共享的是文件夾 FTP&#xff1a;文件服務器samba&#xff1a;不同系統間的文件…

在 Ubuntu 22.04 x64 系統安裝/卸載 1Panel 面板

一、 1Panel 是什么&#xff1f; 1Panel 是一款基于 Go 語言開發的現代化開源服務器管理面板&#xff08;類似寶塔面板&#xff09;&#xff0c;專注于容器化&#xff08;Docker&#xff09;和云原生環境管理&#xff0c;提供可視化界面簡化服務器運維操作。 1. 1Panel主要功…

Redis | Redis集群模式技術原理介紹

關注&#xff1a;CodingTechWork Redis 集群模式概述 Redis 集群&#xff08;Cluster&#xff09;模式是 Redis 官方提供的分布式解決方案&#xff0c;旨在解決單機 Redis 在數據量和性能上的限制。它通過數據分片、高可用性和自動故障轉移等特性&#xff0c;提供了水平擴展和…

Servlet小結

視頻鏈接&#xff1a;黑馬servlet視頻全套視頻教程&#xff0c;快速入門servlet原理servlet實戰 什么是Servlet&#xff1f; 菜鳥教程&#xff1a;Java Servlet servlet&#xff1a; server applet Servlet是一個運行在Web服務器&#xff08;如Tomcat、Jetty&#xff09;或應用…

數據庫進階之MySQL 程序

1.目標 1> 了解mysqlId服務端程序 2> 掌握mysql客戶端程序的使用 3> 了解工具包中的其他程序 2. MySQL程序簡介 本章介紹 MySQL 命令?程序以及在運?這些程序時指定選項的?般語法(如:mysql -uroot -p)。 對常?程序進?詳細的講解(實用工具的使用方法)&#xf…

VS2022 設置 Qt Project Settings方法

本文解決的問題&#xff1a;創建完成后&#xff0c;如需要用到Sql或者Socket等技術&#xff0c;需要設置Qt Project Settings&#xff1b; 1、打開VS2022編譯器&#xff0c;創建QT項目工程 2、創建完成后&#xff0c;點擊 解決方案 →右鍵屬性 3、選擇 Qt Project Settings →…

React:封裝一個評論回復組件

分析 用戶想要一個能夠顯示評論列表&#xff0c;并且允許用戶進行回復的組件。可能還需要支持多級回復&#xff0c;也就是對回復進行再回復。然后&#xff0c;我要考慮組件的結構和功能。 首先&#xff0c;數據結構方面&#xff0c;評論應該包含id、內容、作者、時間&#xf…

wx讀書某sign算法詳解

未加固 版本&#xff1a;9.2.3 前置知識&#xff1a; (v41 & 0xFFFFFFFFFFFFFFFELL) 是一種高效的奇偶檢查方法&#xff0c;用于判斷數值 v41 是否為奇數。 std::sort<std::lessstd::string,std::string &,std::string>(a1, v6, s); 排序算法 # 完全等價的字…

Django的異步任務隊列管理_Celery

1 基本原理 Celery 是一個異步任務隊列&#xff0c;能夠將耗時操作&#xff08;如發郵件、處理圖片、網絡爬蟲等&#xff09;從 Django 主線程中分離出來&#xff0c;由后臺的 worker 處理&#xff0c;避免阻塞請求。Celery 作為獨立運行的后臺進程&#xff08;Worker&#xf…

【計算機網絡】Linux網絡的幾個常用命令

&#x1f4da; 博主的專欄 &#x1f427; Linux | &#x1f5a5;? C | &#x1f4ca; 數據結構 | &#x1f4a1;C 算法 | &#x1f152; C 語言 | &#x1f310; 計算機網絡 相關文章&#xff1a;計算機網絡專欄 目錄 ping&#xff08;檢測網絡連通性&#xff09;…

全開源、私有化部署!輕量級用戶行為分析系統-ClkLog

ClkLog是一款支持私有化部署的全開源埋點數據采集與分析系統&#xff0c;兼容Web、App、小程序多端埋點&#xff0c;快速洞察用戶訪問路徑、行為軌跡&#xff0c;并生成多維用戶畫像。助力中小團隊搭建輕量靈活的用戶行為分析平臺。 為什么需要一款私有化的埋點分析系統&#x…

golang定時器的精度

以 go1.23.3 linux/amd64 為例。 定時器示例代碼&#xff1a; package mainimport ("context""fmt""time" )var ctx context.Contextfunc main() {timeout : 600 * time.Secondctx, _ context.WithTimeout(context.Background(), timeout)dea…

svn 遠程服務搜索功能

svn服務器沒有遠程搜索功能&#xff0c;靠人工檢索耗時耗力&#xff0c;當服務器文件過多時&#xff0c;全部checkout到本地檢索&#xff0c;耗時太久。 1. TortoiseSVN 安裝注意事項 下載官網地址&#xff1a;https://tortoisesvn.en.softonic.com/download 安裝時選中 co…

uniapp-商城-39-shop 購物車 選好了 進行訂單確認4 配送方式2 地址頁面

上面講基本的樣式和地址信息&#xff0c;但是如果沒有地址就需要添加地址&#xff0c;如果有不同的地址就要選地址。 來看看處理方式&#xff0c; 1、回顧 在delivery-layout中 methods:{goAddress(){uni.navigateTo({url:"/pagesub/pageshop/address/addrlist"})…