1. 程式人生 > >關於圖的儲存方法 (靜態鄰接表、前向星、邊集陣列)

關於圖的儲存方法 (靜態鄰接表、前向星、邊集陣列)

一、鄰接矩陣(不多說了)  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]);
	}
}