鏈式前向星、vector存圖


場景設定

想象你是一個社交達人,要記錄你和所有朋友的關系(這就是“圖”)。每個朋友是一個節點,關系是一條邊。你需要快速回答:“我有哪些朋友?”(遍歷鄰居)。


方式1:鏈式前向星(固定小本本)

  • 核心思想:你買了一個固定頁數的筆記本(預分配的數組)。

  • 怎么記?

    1. 給每個朋友一個專屬頁(head[你])。
    2. 每認識一個新朋友,就在筆記本最新空白頁記錄:
      • 朋友名字 (to)
      • 和你的關系 (weight,可選)
      • 關鍵! 還要寫上“上一個記錄在筆記本第幾頁?” (next)
    3. 更新你的專屬頁:寫上最新這條記錄的頁碼
  • 通俗比喻

    • 你的筆記本就是 edges[] 數組(每條邊占一頁)。
    • head[你] 是你名字標簽貼紙指向的最新記錄頁碼。
    • next 就像是“上一條記錄在第幾頁?”的提示。
    • 要查所有朋友?從 head[你] 找到最新記錄,然后根據 next 翻到前一頁,再前一頁…直到沒記錄了(next = -1)。

優點

  1. 省空間(內存少)
    • 筆記本只記核心信息(朋友名、關系、上條頁碼),沒有多余開銷。
    • vector 像活頁夾,每頁本身還有夾子、標簽等額外重量(vector 的容量指針、大小等元數據)。
  2. 加朋友超快(O(1))
    • 直接寫在最新空白頁,更新你的標簽貼紙 (head) 就行。固定操作,永不拖延。
  3. 筆記本整齊(內存連續)
    • 所有記錄按頁碼連續存放。CPU 一次“搬”一摞記錄進緩存效率高(緩存友好),但翻頁查找過程不連續

缺點

  1. 筆記本頁數固定(靜態大小)
    • 買的時候要猜最多交多少朋友。朋友太多?本子寫滿了,得重買更大的本子,全部重抄一遍(重新初始化,擴容麻煩)。
  2. 絕交(刪除邊)超麻煩
    • 想刪掉一個朋友的記錄?你得順著鏈條一頁頁找,找到后還要修改它前后記錄的 next 指向,像拆掉一節火車車廂。幾乎沒人用鏈式前向星刪邊。
  3. 查朋友名單有點慢(遍歷效率)
    • 雖然記錄在物理上是連續的,但你查名單時是根據 next 跳著翻頁(第 5 頁 -> 第 2 頁 -> 第 8 頁)。翻頁動作不連貫,CPU 緩存可能幫不上忙。
  4. 寫起來費勁(代碼復雜)
    • 你得自己維護 head 和每條記錄的 next 指針。寫代碼時容易搞暈,調試也麻煩。

代碼:

#include <bits/stdc++.h> 
using namespace std;
const int N = 1000;  // 最大節點數
const int M = 10000; // 最大邊數// 定義邊的結構體
struct Edge {int to;     // 這條邊指向哪個節點int next;   // 同一個起點的下一條邊的索引(相當于"上一條記錄的頁碼")int w;      // 邊權(可選)
} edges[M];  // 存儲所有邊的數組int head[N]; // head[u] 表示節點 u 的第一條邊的索引(初始為 -1)
int idx = 0;    // 當前邊的索引(相當于"最新空白頁的頁碼")// 添加一條從 u 到 v 的邊,權重為 w
void addEdge(int u, int v, int w) {edges[idx].to = v;       // 記錄這條邊指向 vedges[idx].w = w;        // 記錄邊權edges[idx].next = head[u]; // 新邊的 next 指向 u 原來的第一條邊head[u] = idx++;         // 更新 u 的第一條邊為當前這條邊
}// 遍歷節點 u 的所有鄰居
void printNeighbors(int u) {cout << "節點 " << u << " 的朋友: ";for (int i = head[u]; i != -1; i = edges[i].next) {int v = edges[i].to;int w = edges[i].w;cout << v << "(親密度:" << w << ") ";}cout << endl;
}int main() {memset(head, -1, sizeof(head)); // 初始化 head 數組為 -1(表示空鏈表)// 添加邊:0 -> 1 (權重 5), 0 -> 2 (權重 3), 1 -> 2 (權重 2)addEdge(0, 1, 5);addEdge(0, 2, 3);addEdge(1, 2, 2);// 打印鄰居printNeighbors(0); // 輸出: 節點 0 的朋友: 2(親密度:3) 1(親密度:5)printNeighbors(1); // 輸出: 節點 1 的朋友: 2(親密度:2)return 0;
}

關鍵點

  • head[u] 存儲節點 u最新一條邊的索引(類似鏈表頭指針)。
  • edges[idx] 存儲所有邊,idx 是當前可用的邊索引(類似動態分配的頁數)。
  • next 指向同起點的上一條邊(類似鏈表的前驅指針)。
  • 遍歷時,從 head[u] 開始,沿著 next 走,直到 -1(類似鏈表遍歷)。

適合誰? 朋友數量上限確定(比如競賽題已知最大點數/邊數),追求極致速度和省內存的“極客”。


方式2:Vector 鄰接表(活頁文件夾)

  • 核心思想:你買了一個帶標簽的活頁文件夾。給每個朋友(包括你自己)分配一個專屬分區

  • 怎么記?

    1. 想加一個新朋友“老王”?
    2. 直接找到你自己的分區
    3. 在分區里新加一頁活頁紙,寫上“老王”和你們的關系(vector[你].push_back(Edge{老王, 關系}))。
  • 通俗比喻

    • 文件夾是 vector > graph
    • 每個分區是 graph[你]graph[朋友A]graph[朋友B]
    • 每個分區里的活頁紙就是該節點的所有鄰居邊記錄。

優點

  1. 分區獨立,無限加頁(動態擴容)
    • 你的分區寫滿了?系統自動給你換更大的分區頁夾(vector 自動擴容)。雖然換的時候要復印所有舊頁(復制數據),但均攤下來每次加頁還是很快(均攤 O(1))。
  2. 查朋友名單超快(遍歷高效)
    • 打開你自己的分區,里面的活頁紙按添加順序疊放(內存連續)。你可以一口氣從頭翻到尾,翻頁動作流暢,CPU 緩存瘋狂點贊!
  3. 用起來超簡單(代碼簡潔)
    • 加朋友?一句 graph[你].push_back(老王)。查朋友?一個 for 循環遍歷 graph[你]。邏輯清晰,不易出錯。
  4. 額外功能強大(STL支持)
    • 想按關系親密度排序朋友?直接用 sort(graph[你].begin(), graph[你].end())。想找特定朋友?可以用 find。活頁夾兼容各種“辦公用具”(STL算法)。

缺點

  1. 文件夾本身有點重(內存開銷大)
    • 每個分區(vector)都要維護自己的“目錄”(容量、大小等元數據)。朋友非常多時,比鏈式前向星多占 20%-50% 內存。
  2. 換分區頁夾時手忙腳亂(擴容開銷)
    • 雖然系統自動幫你換,但換的那一刻(擴容)要把所有舊頁復印到新分區,這時添加操作會短暫變慢(雖然均攤后很快,但有波動)。
  3. 撕掉某頁很麻煩(刪除邊低效)
    • 想刪掉分區中間一頁?你得把后面所有頁往前挪一格(vector 刪除中間元素 O(度數))。除非你總是刪最后一頁(pop_back)。
  4. 分區分散(內存不連續)
    • 你的分區、朋友A的分區、朋友B的分區在文件夾里可能不挨著。雖然每個分區內部連續,但訪問不同節點時,CPU 可能要在文件夾里跳來跳去。

適合誰? 朋友數量不確定或經常變,追求代碼好寫、好讀、易維護的“務實派”。絕大多數工程項目的首選。

代碼

#include <bits/stdc++.h>
using namespace std;
const int N = 1000; // 最大節點數// 定義邊的結構體(比鏈式前向星更簡單,不需要 next)
struct Edge {int to; // 這條邊指向哪個節點int w;  // 邊權(可選)
};vector<Edge> graph[N]; // graph[u] 存儲節點 u 的所有鄰居// 添加一條從 u 到 v 的邊,權重為 w
void addEdge(int u, int v, int w) {graph[u].push_back({v, w}); // 直接 push_back 即可
}// 遍歷節點 u 的所有鄰居
void printNeighbors(int u) {cout << "節點 " << u << " 的朋友: ";for (Edge e : graph[u]) {cout << e.to << "(親密度:" << e.w << ") ";}cout << endl;
}int main() {// 添加邊:0 -> 1 (權重 5), 0 -> 2 (權重 3), 1 -> 2 (權重 2)addEdge(0, 1, 5);addEdge(0, 2, 3);addEdge(1, 2, 2);// 打印鄰居printNeighbors(0); // 輸出: 節點 0 的朋友: 1(親密度:5) 2(親密度:3)printNeighbors(1); // 輸出: 節點 1 的朋友: 2(親密度:2)return 0;
}

關鍵點

  • graph[u] 是一個 vector,直接存儲 u 的所有鄰居邊。
  • 添加邊直接用 push_back,無需維護 next 指針。
  • 遍歷時直接 for (Edge e : graph[u]),比鏈式前向星更直觀。

總結

總的來說,兩款存圖方式各有優劣,具體取決于需求和喜好

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

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

相關文章

YAML 中定義 List 的幾種方式

在 YAML 配置文件中定義 List 并在 Spring 應用中注入是非常常見的操作&#xff0c;下面詳細介紹具體寫法和注入方式。一、YAML 中定義 List 的幾種方式1. 縮進式寫法&#xff08;推薦&#xff09;最常用的方式&#xff0c;通過短橫線 - 加空格表示列表項&#xff1a;yaml# app…

C# 反射和特性(自定義特性)

自定義特性 你或許已經注意到了&#xff0c;應用特性的語法和之前見過的其他語法有很大不同。你可能會覺得特 性是一種完全不同的結構類型&#xff0c;其實不是&#xff0c;特性只是一種特殊的類。 有關特性類的一些要點如下。 用戶自定義的特性類叫作自定義特性。所有特性類都…

科目二的四個電路

一.K21電動機單連續運轉接線(帶點動控制)1.電路圖2.主線路這可很明了,是一條直線,從上接到下就OK了,然后從熱繼電器出來,接到SB3按鈕的常閉觸點上接著往下走一端接到SB2的常閉觸點上,接著往下走&#xff0c;走到接觸器的線圈上,從L2借一條火線出來,從熔斷器的上端接入,另一端接…

【位運算】查詢子數組最大異或值|2693

本文涉及知識點 位運算、狀態壓縮、枚舉子集匯總 3277. 查詢子數組最大異或值 給你一個由 n 個整數組成的數組 nums&#xff0c;以及一個大小為 q 的二維整數數組 queries&#xff0c;其中 queries[i] [li, ri]。 對于每一個查詢&#xff0c;你需要找出 nums[li…ri] 中任…

HTML DOM 方法

HTML DOM 方法 引言 HTML DOM&#xff08;文檔對象模型&#xff09;是HTML文檔的編程接口&#xff0c;它允許開發者通過JavaScript來操作HTML文檔中的元素。DOM 方法是DOM編程的核心&#xff0c;它提供了豐富的操作手段來改變網頁的結構、樣式和行為。本文將詳細介紹HTML DOM中…

w嵌入式分享合集68

自己的原文哦~ https://blog.51cto.com/whaosoft/14133002 一、一鍵開關機電路的設計方案 方案一&#xff1a;電路圖 一鍵開關機電路分析如下&#xff1a; 電路工作流程如下&#xff1a; Key按下瞬間&#xff0c;Q2、Q1導通&#xff0c;7805輸入電壓在8.9V左右&…

FFmpeg QoS 處理

FFmpeg 中的 QoS (服務質量) 處理主要關注于實時流媒體傳輸中的時序控制、丟幀策略和網絡適應等方面。以下是 FFmpeg 中 QoS 相關的關鍵機制和配置方法。1. 基本 QoS 機制丟幀策略 (Frame Dropping)cAVDictionary *options NULL; av_dict_set(&options, "framedrop&q…

TexStudio中的Latex,PDFLatex,XeLatex和LuaLatex的區別

多種LaTeX編譯器一、多種LaTeX編譯器 1.1 PDFLaTeX&#xff08;1994年&#xff09; 默認、最常用的引擎。 輸入文件通常是 ASCII 或 UTF-8 編碼&#xff08;但中文需要 CJK 宏包或 ctex 宏包支持&#xff09;。 字體選擇受限&#xff1a;只能使用 TeX 自帶的字體或者 Type 1…

容器化部署:用Docker封裝機器翻譯模型與服務詳解

文章目錄一、機器翻譯容器化的技術棧選型1.1 為什么需要容器化MT模型&#xff1f;1.2 基礎鏡像選擇對比1.3 典型依賴分層方案1.4 性能對比&#xff08;容器化 vs 原生部署&#xff09;二、關鍵部署模式2.1 輕量級API服務封裝2.2 模型熱更新策略三、Docker鏡像構建3.1 編寫Docke…

leetcode_42 接雨水

1. 題意 給定 n 個非負整數表示每個寬度為 1 的柱子的高度圖&#xff0c;計算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 2. 題解 這個題不會做&#xff0c;全部是看得題解捏。 不過能看懂題解感覺自己也很棒了&#xff01; 看完題解后感覺最難的是如何求出有多少…

Spring Boot 整合 Thymeleaf 模板引擎:從零開始的完整指南

引言&#xff1a;為什么選擇 Thymeleaf&#xff1f; Thymeleaf 是一個現代化的服務器端 Java 模板引擎&#xff0c;專為 Web 開發而設計。與 JSP 不同&#xff0c;Thymeleaf 模板是純 HTML 文件&#xff0c;可以直接在瀏覽器中預覽&#xff0c;無需后端服務器支持。這種"…

pytest介紹(python測試框架)(@pytest.mark.parametrize、@pytest.fixtures)

文章目錄**1. 核心特點**- **簡潔易用**&#xff1a;無需復雜的配置&#xff0c;只需編寫簡單的函數或類即可進行測試。- **豐富的斷言**&#xff1a;直接使用 Python 內置的 assert 語句&#xff0c;失敗時提供詳細的錯誤信息。- **自動發現測試**&#xff1a;通過約定的命名規…

[Python 基礎課程]繼承

在 Python 的面向對象編程&#xff08;OOP&#xff09;中&#xff0c;繼承&#xff08;Inheritance&#xff09; 是一種重要的機制&#xff0c;它允許一個類&#xff08;稱為子類或派生類&#xff09;從另一個類&#xff08;稱為父類、基類或超類&#xff09;中繼承屬性和方法。…

QT之設計器組件功能(8大類55個組件)

組件名稱 功能描述關鍵屬性1. Layouts&#xff08;布局組件&#xff09;(1) Vertical Layout&#xff08;垂直布局&#xff09;將子控件按垂直方向依次排列layoutSpacing&#xff1a;控件之間的間距layoutMargin&#xff1a;布局邊緣的邊距layoutStretch&#xff1a;設置各控件…

java中list的api詳細使用

在Java中&#xff0c;List是集合框架中最常用的接口之一&#xff0c;繼承自Collection&#xff0c;代表有序、可重復的元素集合&#xff08;允許null元素&#xff09;。其核心實現類有ArrayList&#xff08;數組實現&#xff0c;隨機訪問高效&#xff09;、LinkedList&#xff…

Azure AI Search 探索總結

Azure AI Search 原名 Azure Cognitive Service&#xff0c;是Azure中用來給AI項目構建知識庫的組件。知識庫本質和數據庫很像&#xff0c;但是內部的存儲結構和檢索算法不一樣。比如并不是知識庫的每一列都可以用來過濾、檢索或group by&#xff0c;而是要根據實際情況配置。A…

高效解決 pip install 報錯 SSLError: EOF occurred in violation of protocol

高效解決 pip install 報錯 SSLError: EOF occurred in violation of protocol 標簽&#xff1a; Python, pip, SSLError, Clash, 網絡代理, 問題解決 一、問題描述 在Python開發中&#xff0c;pip 是我們最親密的伙伴。然而&#xff0c;當你身處需要科學上網的環境&#xff0c…

CSS 核心知識點全解析:從基礎到實戰應用

大家好&#xff01;今天這篇文章將系統總結 CSS 的核心知識點&#xff0c;從最基礎的樣式引入到復雜的選擇器應用&#xff0c;再到盒子模型、文本處理等實戰技巧&#xff0c;全程結合代碼示例&#xff0c;讓你輕松掌握 CSS 的精髓。一、CSS 是什么&#xff1f;為什么需要它&…

ClickHouse的學習與了解

什么是ClickHouse&#xff1f; ClickHouse是一個用于聯機分析(OLAP)的列式數據庫管理系統(DBMS)。 在傳統的行式數據庫系統中&#xff0c;數據按如下順序存儲&#xff1a;RowWatchIDJavaEnableTitleGoodEventEventTime#0893543506621Investor Relations12016/5/18 5:19#1903295…

安卓11 12系統修改定制化_____修改系統 解鎖system分區 去除data加密 自由刪減系統應用

在定制化系統中。修改系統分區 解鎖system。讓用戶可以自由刪減應用。這個在定制化服務中比較常見。對于此項修改服務。需要我們了解基礎的分區常識以及常用的幾種基礎修改步驟。 通過博文了解?????? 1??????-----修改rom 解鎖 system 分區有什么意義 2????…