1. 程式人生 > >樹、簡單圖的儲存方法——鄰接矩陣 鄰接表 和 鏈式前向星 學習筆記

樹、簡單圖的儲存方法——鄰接矩陣 鄰接表 和 鏈式前向星 學習筆記

ps:樹是一種特殊的圖,樹有自己特殊的儲存方式,圖的儲存方式都能應用於樹。

對於圖、樹來講,一般給出一個n表是有n個節點(標號1~n)m個二元組(a,b)表示ab之間有一條邊。這樣就能確定一個圖。

對於樹來講沒有環,所以m=n-1

part one、鄰接矩陣

鄰接矩陣的優點是可以O(1)查出兩點之間有沒有邊,缺點是無法高效的查詢某個點的所有邊,且對於稀疏圖來講浪費了大量的空間(存了很多0)。

    使用mp[maxn][maxn]二維陣列儲存,mp[i][j]=0表示節點i,j之間不直接相連,為1表示有一條邊相連(當然對於簡單圖來說只能為1和0)。

int a,b,n,m; cin>>n>>m; memset(mp,0,sizeof(mp));//清0  for(int i=0;i<n;i++){     scanf("%d%d",&a,&b);//a和b之間有邊     mp[a][b]=mp[b][a]=1;//無向圖兩個都要賦值  }

這樣圖就存好並可以使用了。

part two、鄰接表

鄰接表可以最高效率地查詢某個點的所有邊,但是無法高效地查詢兩個點之間是否有邊。

使用連結串列儲存(實際應用時為了方便用vector):只記錄與點i有邊的點,這樣相當於記錄邊。相當於弱化的十字連結串列(多用了空間)

vector<int>mp[maxn]; cin>>n>>m; for(int i=1;i<=m;i++){     scanf("%d%d",&a,&b);     mp[a].push_back(b);     mp[b].push_back(a); } 

part three、鏈式前向星

前向星也是儲存邊。個人認為前向星只是鄰接表的另一種寫法,陣列模擬連結串列空間分配(記憶體池)的一種寫法。

好像單純學前向星沒有什麼創新的知識,但由於看網上程式碼尤其是樹鏈剖分和lca很多都用鏈式前向星的寫法,還是老老實實理解一下前向星書寫套路。

其實照著鄰接表的思路理解鏈式前向星就很容易了(吐槽一下為什麼起一個這麼貌似高大上的名字,老老實實叫鄰接表不好嗎

const int maxn = 10005; const int maxm = 1000005;//edge using namespace std; int n; struct node {//儲存邊的資料結構,to是點,next是指標。      int to, next;     //    int value ,from,   }; node edge[maxm];//儲存邊的陣列,兼任記憶體池。  int box[maxn];//記錄節點i鄰接表第一個成員指標,使用頭插法。  int ecnt;//邊的個數 inline void _make_map(int from, int to) {  //建立從from到to的一條單向邊,若無向圖則正反建立兩條。 頭插法      edge[ecnt].to = to;//to  節點     edge[ecnt].next = box[from];//同節點下該邊下一條邊     box[from] = ecnt++;// 節點from的第一條邊 } inline void make_map(int from, int to)//雙向邊 {     _make_map(from, to);//正反向兩次雙向邊      _make_map(to, from); } int main() {     while (scanf("%d", &n) != EOF) {         ecnt = 0;         int i;         int u[100], v[100];         // 儲存邊         for (i = 0; i < n; i++) {             scanf("%d%d", &u[i], &v[i]);             make_map(u[i], v[i]);         }                 }     return 0; }