圖的鄰接表標記法類似於樹的孩子鏈表標記法。對於圖G中的每個頂點vi,該方法把所有鄰接於vi的頂點vj鏈成一個帶頭結點的單鏈表,這個單鏈表就稱為頂點vi的鄰接表(Adjacency List)。
1. 鄰接表的結點結構
(1)表結點結構
┌────┬───┐
│adjvex │next │
└────┴───┘
鄰接表中每個表結點均有兩個域:
① 鄰接點域adjvex
存放與vi相鄰接的頂點vj的序號j。
② 鏈域next
將鄰接表的所有表結點鏈在一起。
注意:
若要表示邊上的資訊(如權值),則在表結點中還應增加一個資料域。
(2)頭結點結構
┌────┬─────┐
│vertex │firstedge │
└────┴─────┘
頂點vi鄰接表的頭結點包含兩個域:
① 頂點域vertex
存放頂點vi的資訊
② 指標域firstedge
vi的鄰接表的頭指標。
注意:
① 為了便於隨機訪問任一頂點的鄰接表,將所有頭結點順序儲存在一個向量中就構成了圖的鄰接表表示。
② 有時希望增加對圖的頂點數及邊數等屬性的描述,可將鄰接表和這些屬性放在一起來描述圖的儲存結構。
2.代碼執行個體
#include<iostream><br />using namespace std;<br />#define MAX_VERTEX_NUM 50//定義圖的最大頂點數<br />typedef char VertexData;<br />typedef struct EdgeNode//表結點<br />{<br />int adjvex;//鄰接點域<br />VertexData data;<br />EdgeNode *next;//邊結點所對應的下一個邊結點<br />} EdgeNode;<br />typedef struct VertexNode//頭結點<br />{<br />VertexData data;<br />EdgeNode *firstedge;//頭結點所對應的第一個邊結點<br />}VertexNode;<br />typedef struct AdjList<br />{<br />int VexNum,ArcNum;//定義圖的頂點數和邊數<br />VertexNode vertex[MAX_VERTEX_NUM];//定義頭結點數組。<br />}AdjList;<br />void CreateGraph(AdjList *adj,int *n)<br />{<br />int e,s,d;<br />cout<<"輸入頂點數和邊數"<<endl;<br />cin>>*n>>e;//輸入頂點數和邊數。<br />adj->VexNum=*n;<br />adj->ArcNum=e;<br />EdgeNode *q=NULL;<br />//初始化表頭結點<br />int i;<br />for(i=1;i<=*n;i++)<br />{<br />cout<<"輸入第"<<i<<"個結點的頂點名稱"<<endl;<br />cin>>adj->vertex[i].data;//頂點名稱,是一個字元<br />adj->vertex[i].firstedge=NULL;<br />}<br />for(i=1;i<=e;i++)<br />{<br /> cout<<"輸入第"<<i<<"條邊的起點和終點"<<endl;<br />cin>>s>>d;//輸入邊的起始和終止<br /> // cout<<"輸入表結點資訊"<<endl;<br />q=(EdgeNode *)malloc(sizeof(EdgeNode));//建立一個表結點<br />if(q==NULL)<br />return;<br />q->adjvex=d;<br />//cin>>q->data;<br />q->next=adj->vertex[s].firstedge;//新加入的節點都是在頭結點之後,原來在頭結點之後的節點要後移。<br />adj->vertex[s].firstedge=q;<br />}<br />}<br />void DisplayGraph(AdjList *adj)<br />{<br />int n=adj->VexNum;//頂點個數,後面要遍曆每一個點點<br />EdgeNode *q=NULL;<br />int i;<br />for( i=1;i<=n;i++)<br />{<br />//cout<<n<<endl;<br />q=adj->vertex[i].firstedge;<br />if(q==NULL)//表示頭結點後面沒有跟其他結點<br />{<br />cout<<"沒用從"<<adj->vertex[i].data<<"出發的節點"<<endl;<br />}<br />else<br />{<br />cout<<"從結點"<<adj->vertex[i].data<<"出發的邊有"<<endl;<br />while(q!=NULL)<br />{<br />//cout<<adj->vertex[i].data<<"->"<<q->data<<endl;<br />cout<<adj->vertex[i].data<<"->"<<adj->vertex[q->adjvex].data<<endl;<br />q=q->next;<br />}<br />}<br />}<br />}<br />void main()<br />{<br />int n;<br />AdjList *adj=(AdjList *)malloc(sizeof(AdjList));<br />CreateGraph(adj,&n);<br />DisplayGraph(adj);<br />//cout<<"hello world!"<<endl;<br />}
輸出結果為:
輸入頂點數和邊數<br />6 6<br />輸入第1個結點的頂點名稱<br />a<br />輸入第2個結點的頂點名稱<br />b<br />輸入第3個結點的頂點名稱<br />c<br />輸入第4個結點的頂點名稱<br />d<br />輸入第5個結點的頂點名稱<br />e<br />輸入第6個結點的頂點名稱<br />f<br />輸入第1條邊的起點和終點<br />1 3<br />輸入第2條邊的起點和終點<br />2 4<br />輸入第3條邊的起點和終點<br />2 1<br />輸入第4條邊的起點和終點<br />4 3<br />輸入第5條邊的起點和終點<br />3 6<br />輸入第6條邊的起點和終點<br />3 5<br />從結點a出發的邊有<br />a->c<br />從結點b出發的邊有<br />b->a<br />b->d<br />從結點c出發的邊有<br />c->e<br />c->f<br />從結點d出發的邊有<br />d->c<br />沒用從e出發的節點<br />沒用從f出發的節點
3.代碼執行個體2(ps:補充於2011-6-14)
總體而言,鄰接表標記法中主要含有兩種結點,分別是頭結點和表結點(也叫做邊結點),在頭結點(s)到表結點(d)之間存在著一條邊。如果頭結點後面有多個表結點,即s->d1->d2,則表示存在著兩條邊,分別是e(s,d1)和e(s,d2)。鄰接表標記法中,頭結點的數量是固定的,就是圖中的頂點數量V,表結點的數量由邊的數量來決定。如果是有向圖,表結點的數量=邊的數量;如果是無向圖,則表結點的數量=邊的數量*2。
在構造圖的時候,如果一個頭結點後面有多個表結點,那麼表結點按次序添加在頭結點後面。比如原先有結構s->d1->d2,現在需要添加表結點d3,那麼需要打斷s->d1的指標,讓d3指向d1,s指向d3。即s->d3->d1->d2。
#include<iostream><br />#include<stdlib.h><br />using namespace std;<br />#define MAX_VERTEX_NUM 50//定義圖的最大頂點數<br />typedef char VertexData;//頂點名稱是字元型。<br />typedef struct EdgeNode//表結點<br />{<br />int adjvex;//鄰接點域<br />VertexData data;<br />EdgeNode *next;//表結點所對應的下一個表結點<br />} EdgeNode;<br />typedef struct VertexNode//頭結點<br />{<br />VertexData data;<br />EdgeNode *firstedge;//頭結點所對應的第一個表結點<br />}VertexNode;<br />typedef struct AdjList//圖的資料結構<br />{<br />int VexNum,ArcNum;//定義圖的頂點數和邊數<br />VertexNode vertex[MAX_VERTEX_NUM];//定義頭結點數組。<br />}AdjList;<br />void CreateGraph(AdjList *adj)<br />{<br />int s,d;<br />int i;<br />cout<<"輸入頂點數和邊數"<<endl;<br />cin>>adj->VexNum>>adj->ArcNum;//輸入圖的頂點數和邊數。<br />EdgeNode *q=NULL;//定義表結點<br />//初始化表頭結點<br />cout<<"輸入"<<adj->VexNum<<"個頭結點的名稱"<<endl;<br />for(i=1;i<=adj->VexNum;i++)<br />{<br />//adj->vertex[i]是頭結點數組<br />cin>>adj->vertex[i].data;//頂點名稱,是一個字元<br />adj->vertex[i].firstedge=NULL;//初始狀態下頭結點後面不跟表結點,因此firstedge=null<br />}<br />//在初始化頭結點以後,就需要開始將表結點添加到頭結點後面去。<br />cout<<"輸入"<<adj->ArcNum<<"條邊的起點和終點"<<endl;<br />for(i=1;i<=adj->ArcNum;i++)<br />{<br />cin>>s>>d;//輸入邊的起始和終止,起始s就是頭結點位置,終止d就是表結點位置<br />q=(EdgeNode *)malloc(sizeof(EdgeNode));//建立一個表結點,為其分配空間<br />if(q==NULL)<br />return;<br />/*<br />如果原來的鏈表是s->a->b-c>,現在要加入一個表結點q,那麼加入以後就變成了s->q->a->b->c<br />因此:<br />1.q所指向的應該是當前s所指向的元素。<br />2.q的鄰接點域是d<br />3.s的指標指向q<br />操作如以下三行代碼<br />*/<br />q->adjvex=d;//表結點的鄰接點域是d<br />q->next=adj->vertex[s].firstedge;//新加入的節點都是在頭結點之後,原來在頭結點之後的節點要後移。<br />adj->vertex[s].firstedge=q;<br />}<br />}<br />void DisplayGraph(AdjList *adj)<br />{<br />int n=adj->VexNum;//頂點個數,後面要遍曆每一個點點<br />EdgeNode *q=NULL;<br />int i;<br />for( i=1;i<=adj->VexNum;i++)<br />{<br />//cout<<n<<endl;<br />q=adj->vertex[i].firstedge;//q為頭結點i所指向的表結點,i->q之間存在邊<br />if(q==NULL)//表示頭結點後面沒有跟其他結點<br />{<br />cout<<"沒用從"<<adj->vertex[i].data<<"出發的節點"<<endl;<br />}<br />else<br />{<br />cout<<"從結點"<<adj->vertex[i].data<<"出發的邊有"<<endl;<br />while(q!=NULL)<br />{<br />//cout<<adj->vertex[i].data<<"->"<<q->data<<endl;<br />cout<<adj->vertex[i].data<<"->"<<adj->vertex[q->adjvex].data<<endl;<br />q=q->next;//鏈表往後跳<br />}<br />}<br />}<br />}<br />void main()<br />{<br />int n;<br />AdjList *adj=(AdjList *)malloc(sizeof(AdjList));<br />CreateGraph(adj);<br />DisplayGraph(adj);<br />system("pause");<br />}<br />/*<br />輸入頂點數和邊數<br />6 6<br />輸入6個頭結點的名稱<br />a b c d e f<br />輸入6條邊的起點和終點<br />1 3<br />2 4<br />2 1<br />4 3<br />3 6<br />3 5<br />從結點a出發的邊有<br />a->c<br />從結點b出發的邊有<br />b->a<br />b->d<br />從結點c出發的邊有<br />c->e<br />c->f<br />從結點d出發的邊有<br />d->c<br />沒用從e出發的節點<br />沒用從f出發的節點<br />請按任意鍵繼續. . .<br />*/