C++U7-06-圖的進階儲存

小虾同学發表於2024-05-26

上節課作業講解:

連結:https://pan.baidu.com/s/1A3Y5_12IgwYbmuep0Q2w6Q?pwd=0000
提取碼:0000

鄰接表和鏈式前向星都是圖論中用於表示圖的常用資料結構,它們各自有特定的特點和用途。以下是對這兩種資料結構的詳細解釋:

鄰接表

定義與特點:

  • 鄰接表是用來表示有限圖的無序列表的集合,每個列表描述了圖中相鄰頂點的集合。
  • 鄰接表是計算機程式中幾種常用圖的表示法之一,特別是在需要儲存大型圖時。
  • 鄰接表是一種順序分配和鏈式分配相結合的儲存結構。如果某個頂點存在相鄰頂點,則把相鄰頂點依次存放於該頂點所指向的單向連結串列中。
  • 對於無向圖,使用鄰接表進行儲存會出現資料冗餘,因為無向圖中的邊是雙向的,所以每個邊會在兩個頂點的鄰接表中各出現一次。
  • 鄰接表通常用於表示稀疏圖,因為它可以節省儲存空間。

實現細節:

  • 在鄰接表中,圖的每個頂點都與一個連結串列相關聯,連結串列中的每個節點表示與該頂點相鄰的一個頂點。
  • 鄰接表可以用陣列和連結串列來實現,其中陣列用於儲存頂點,連結串列用於儲存與每個頂點相鄰的頂點。
  • 鄰接表的一個變體是使用雜湊表(雜湊表)將圖中的每個頂點與相鄰頂點的陣列做關聯,這種實現方法中沒有將邊明確表示為物件。

數字資訊:

  • 對於一個具有n個頂點和e條邊的無向圖,鄰接表表示中會有n個頂點表結點和2e個邊表結點(因為每條邊在鄰接表中會出現兩次)。
  • 對於有向圖,鄰接表表示中會有n個頂點表結點和e個邊表結點(因為有向圖是單向的)。

鏈式前向星

定義與特點:

  • 鏈式前向星是一種特殊的邊集陣列,與鄰接表的思想相似,但實現方式略有不同。
  • 鏈式前向星使用結構體陣列來實現,是靜態的,需要在一開始就知道資料範圍並開好陣列大小。
  • 鏈式前向星避免了鄰接表在新增邊時可能需要的動態記憶體分配,因此在某些情況下可能更加高效。

實現細節:

  • 鏈式前向星中,邊被儲存在一個結構體陣列中,每個結構體包含邊的終點、下一條同起點邊的索引以及邊的權值(如果有的話)。
  • 透過一個額外的陣列(通常稱為head陣列)來記錄每個頂點作為起點時的第一條邊的索引。
  • 新增邊時,只需要在結構體陣列中分配一個新的位置,並更新head陣列和相應邊的next指標。

與鄰接表的比較:

  • 鄰接表更加靈活,可以動態地增加邊,而鏈式前向星則需要在一開始就知道資料範圍。
  • 鏈式前向星在記憶體使用上可能更加緊湊,因為它避免了鄰接表中可能出現的連結串列指標的空間開銷。
  • 在實現上,鏈式前向星通常比鄰接表更加直觀和易於理解,因為它直接使用陣列來儲存邊和頂點資訊。

總結來說,鄰接表和鏈式前向星都是用於表示圖的有效資料結構,它們各有優缺點,適用於不同的場景和需求。在選擇使用哪種資料結構時,需要根據具體的應用場景和效能要求來進行權衡。

複習圖

鄰接表存圖

鏈式前向星的存圖方式

過程如果忘了就問問老師

鏈式前向星存圖構建程式碼

[【圖的儲存】有向圖的權重]

鄰接表和鏈式前向星兩種方式程式碼

C++U7-06-圖的進階儲存
【演算法分析】
用鄰接表將圖儲存,然後以列舉每個點,將從每個點開始的邊的權值進行相加。

【參考程式碼】
//vector陣列
#include<bits/stdc++.h>
using namespace std;

struct node {
    int v, w;
};
vector<node> ve[109];
int main() {
    int n, m;
    cin >> n >> m;
    while (m--) {
        int u, v, w;
        cin >> u >> v >> w;
        ve[u].push_back({ v,w });
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < ve[i].size(); j++) {
            ans += ve[i][j].w;
        }
    }
    cout << ans;
    return 0;
}

//鏈式前向星
#include<bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;
struct node {
    int to; // 終點
    int next; // 下一個位置
    int w; // 權重
} edge[N]; // 邊結構體陣列
int head[N]; // 連結串列陣列,頂點連結串列起始位置
int cnt; // 當前的已加入的邊數
// 插入一條新邊,起點為 u
void add(int u, int v, int w) {
    // 表示新邊的結點
    edge[++cnt].to = v;
    edge[cnt].w = w;
    // 新結點指向 u 的連結串列的鏈頭
    edge[cnt].next = head[u];
    // 新結點作為新的鏈頭
    head[u] = cnt;
}
int main() {
    int n, m;
    cin >> n >> m;
    while (m--) {
        int u, v, w;
        cin >> u >> v >> w;
        add(u, v, w); // 新增邊
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = head[i]; j; j = edge[j].next) {
            ans += edge[j].w;
        }
    }
    cout << ans;
    return 0;
}
View Code

[【圖的儲存】公路查詢]

C++U7-06-圖的進階儲存
【演算法分析】
用鄰接表將圖儲存。如果採用 vector 陣列存圖,由於題目要求後記錄的邊先輸出,因此需要逆序遍歷。鏈式前向星本身就是後記錄的邊再前面。

【參考程式碼】
//vector陣列
#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 10;
struct node {
    int v, w;
};
vector<node> ve[maxn];
int main() {
    int n, m, q;
    cin >> n >> m >> q;
    for (int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        ve[u].push_back({ v,w });
    }
    while (q--) {
        int x;
        cin >> x;
        for (int i = (int)ve[x].size() - 1; i >= 0; i--) {
            cout << ve[x][i].v << " " << ve[x][i].w << '\n';
        }
    }
    return 0;
}

//鏈式前向星
#include<bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;
struct node {
    int to; // 終點
    int next; // 下一個位置
    int w; // 權重
} edge[N]; // 邊結構體陣列
int head[N]; // 連結串列陣列,頂點連結串列起始位置
int cnt; // 當前的已加入的邊數
// 插入一條新邊,起點為 u
void add(int u, int v, int w) {
    // 表示新邊的結點
    edge[++cnt].to = v;
    edge[cnt].w = w;
    // 新結點指向 u 的連結串列的鏈頭
    edge[cnt].next = head[u];
    // 新結點作為新的鏈頭
    head[u] = cnt;
}
int main() {
    int n, m, q;
    cin >> n >> m >> q;
    for (int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        add(u, v, w); // 新增邊
    }
    while (q--) {
        int x;
        cin >> x;
        for (int j = head[x]; j; j = edge[j].next) {
            cout << edge[j].to << " " << edge[j].w << '\n';
        }
    }
    return 0;
}
View Code

作業講解:

連結:https://pan.baidu.com/s/1eVLnEcN3HOAK4tL_iIZiGQ?pwd=0000
提取碼:0000

相關文章