關於圖的儲存方法 (靜態鄰接表、前向星、邊集陣列)
阿新 • • 發佈:2019-02-06
一、鄰接矩陣(不多說了) G[u][v]
二、鄰接表
1、動態連結串列(指標) 一個數組表頭(u)+ struct結點(v),相鏈,若有權值等資訊再在結點裡加相應域。
2、靜態連結串列(陣列) first陣列(模擬表頭、u)+ 邊集陣列(編號e,u、v)+ next陣列(模擬指標相指)。這個跟1看似有點區別(前者鏈的是點,後者鏈的是邊),其實是沒區別,因為要用陣列實現連結串列,所以對1中所有結點實行e編號,意義就是“邊”。
通常實現方法: 開五個陣列 first[MAXN]; u[MAXM], v[MAXM], w[MAXM], next[MAXM]。
三、邊集陣列
就是把所有邊放在一個數組裡,這樣就可以完成遍歷所有邊的操作了(很土吧= =)。通常要根據實際需要做一些輔助儲存。
1、上面的陣列實現鄰接表就是邊集陣列再加上first陣列和next陣列。
2、前向星。跟1很相似的,區別是他對邊集陣列按u點(前一個端點)升序排序,使得由同一個點出發的邊都集中在一起了。再加上輔助陣列 f[MAXN](跟前面first陣列類似的作用),存 結點i 出發的第一個邊在邊集數組裡的位置。
所以注意到,前向星其實就是做了一個緊縮儲存的處理,並且通過一次排序,省掉了next陣列(靜態鄰接表)。當然也可以不排序,多維護一個next陣列。
通常實現方法:開四個陣列 f[MAXN]; u[MAXM], v[MAXM], w[MAXM]。
附:
①靜態鄰接表+Dijkstra+heap
// Dijkstra+靜態鄰接表 #include<cstdio> #include<cstring> #include<iostream> #include<queue> using namespace std; #define MAXN 100 #define MAXM 100 #define INF 1<<30 typedef pair<int, int> pii; //(dist[v], v) priority_queue<pii, vector<pii>, greater<pii> > q; int first[MAXN]; int u[MAXM], v[MAXM], w[MAXM], next[MAXM]; int dist[MAXN], ins[MAXN]; // ins[] 是否在s集合中 int n, m; void dijkstra(int st) { for(int i=0; i<n; i++) dist[i] = i==st? 0: INF; memset(ins, 0, sizeof(ins)); q.push(make_pair(dist[st], st)); // ins[st] = 1; //別跟spfa inq弄混,在優先佇列裡取出來才算是ins了 while(!q.empty()) { pii p = q.top(); q.pop(); int x = p.second; if(!ins[x]) { ins[x] = 1; for(int i=first[x]; i!=-1; i=next[i]) { if(dist[v[i]] > dist[x]+w[i]) //relax { dist[v[i]] = dist[x] + w[i]; q.push(make_pair(dist[v[i]], v[i])); } } } }//end of while } void read_graph() { scanf("%d%d", &n, &m); memset(first, -1, sizeof(first)); for(int i=0; i<m; i++) { scanf("%d%d%d", &u[i], &v[i], &w[i]); next[i] = first[u[i]]; first[u[i]] = i; } } int main() { read_graph(); int st; dijkstra(scanf("%d", &st)); for(int i=0; i<n; i++) { printf("[%d,%d]=%d\n", st, i, dist[i]); } }
②靜態鄰接表+spfa
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
#define MAXN 100
#define MAXM 100
#define INF 1<<30
queue<int> q;
int first[MAXN], next[MAXM];
struct edge
{
int u, v, w;
}a[MAXM];
int dist[MAXN], inq[MAXN];
int n, m;
void spfa(int st)
{
for(int i=0; i<n; i++) dist[i] = i==st? 0: INF;
memset(inq, 0, sizeof(inq));
q.push(st);
inq[st] = 1; //反正馬上就出隊,這個inq可以不要
while(!q.empty())
{
int u = q.front(); q.pop();
inq[u] = 0;
for(int e=first[u]; e!=-1; e=next[e])
{
int v = a[e].v;
if(dist[v] > dist[u]+a[e].w)
{
dist[v] = dist[u]+a[e].w;
if(!inq[v]) { q.push(v); inq[v] = 1; } //inq=1 !!!!
}
}
}
}
void read_graph()
{
cin>>n>>m;
memset(first, -1, sizeof(first)); //別忘了初始化 表頭
for(int e=0; e<m; e++)
{
cin>>a[e].u>>a[e].v>>a[e].w;
next[e] = first[a[e].u];
first[a[e].u] = e;
}
}
int main()
{
read_graph();
int st;
cin>>st;
spfa(st);
for(int i=0; i<n; i++)
{
printf("[%d,%d]=%d\n", st, i, dist[i]);
}
}