有向图的邻接表表示法
圖的鄰接表表示法類似于樹的孩子鏈表表示法。對(duì)于圖G中的每個(gè)頂點(diǎn)vi,該方法把所有鄰接于vi的頂點(diǎn)vj鏈成一個(gè)帶頭結(jié)點(diǎn)的單鏈表,這個(gè)單鏈表就稱為頂點(diǎn)vi的鄰接表(Adjacency List)。
1. 鄰接表的結(jié)點(diǎn)結(jié)構(gòu)
(1)表結(jié)點(diǎn)結(jié)構(gòu)
? ??┌────┬───┐?
? ??│adjvex??│next??│
? ? └────┴───┘
? ? 鄰接表中每個(gè)表結(jié)點(diǎn)均有兩個(gè)域:
① 鄰接點(diǎn)域adjvex
存放與vi相鄰接的頂點(diǎn)vj的序號(hào)j。
② 鏈域next
將鄰接表的所有表結(jié)點(diǎn)鏈在一起。
??注意:
? ? 若要表示邊上的信息(如權(quán)值),則在表結(jié)點(diǎn)中還應(yīng)增加一個(gè)數(shù)據(jù)域。
(2)頭結(jié)點(diǎn)結(jié)構(gòu)
? ??┌────┬─────┐?
? ??│vertex??│firstedge │
? ? └────┴─────┘
? ? 頂點(diǎn)vi鄰接表的頭結(jié)點(diǎn)包含兩個(gè)域:
① 頂點(diǎn)域vertex
存放頂點(diǎn)vi的信息
② 指針域firstedge
vi的鄰接表的頭指針。
??注意:
? ? ① 為了便于隨機(jī)訪問任一頂點(diǎn)的鄰接表,將所有頭結(jié)點(diǎn)順序存儲(chǔ)在一個(gè)向量中就構(gòu)成了圖的鄰接表表示。
? ? ② 有時(shí)希望增加對(duì)圖的頂點(diǎn)數(shù)及邊數(shù)等屬性的描述,可將鄰接表和這些屬性放在一起來描述圖的存儲(chǔ)結(jié)構(gòu)。
2.代碼實(shí)例
#include<iostream> using namespace std; #define MAX_VERTEX_NUM 50//定義圖的最大頂點(diǎn)數(shù) typedef char VertexData; typedef struct EdgeNode//表結(jié)點(diǎn) { int adjvex;//鄰接點(diǎn)域 VertexData data; EdgeNode *next;//邊結(jié)點(diǎn)所對(duì)應(yīng)的下一個(gè)邊結(jié)點(diǎn) } EdgeNode; typedef struct VertexNode//頭結(jié)點(diǎn) { VertexData data; EdgeNode *firstedge;//頭結(jié)點(diǎn)所對(duì)應(yīng)的第一個(gè)邊結(jié)點(diǎn) }VertexNode; typedef struct AdjList { int VexNum,ArcNum;//定義圖的頂點(diǎn)數(shù)和邊數(shù) VertexNode vertex[MAX_VERTEX_NUM];//定義頭結(jié)點(diǎn)數(shù)組。 }AdjList; void CreateGraph(AdjList *adj,int *n) { int e,s,d; cout<<"輸入頂點(diǎn)數(shù)和邊數(shù)"<<endl; cin>>*n>>e;//輸入頂點(diǎn)數(shù)和邊數(shù)。 adj->VexNum=*n; adj->ArcNum=e; EdgeNode *q=NULL; //初始化表頭結(jié)點(diǎn) int i; for(i=1;i<=*n;i++) { cout<<"輸入第"<<i<<"個(gè)結(jié)點(diǎn)的頂點(diǎn)名稱"<<endl; cin>>adj->vertex[i].data;//頂點(diǎn)名稱,是一個(gè)字符 adj->vertex[i].firstedge=NULL; } for(i=1;i<=e;i++) { cout<<"輸入第"<<i<<"條邊的起點(diǎn)和終點(diǎn)"<<endl; cin>>s>>d;//輸入邊的起始和終止 // cout<<"輸入表結(jié)點(diǎn)信息"<<endl; q=(EdgeNode *)malloc(sizeof(EdgeNode));//創(chuàng)建一個(gè)表結(jié)點(diǎn) if(q==NULL) return; q->adjvex=d; // cin>>q->data; q->next=adj->vertex[s].firstedge;//新加入的節(jié)點(diǎn)都是在頭結(jié)點(diǎn)之后,原來在頭結(jié)點(diǎn)之后的節(jié)點(diǎn)要后移。 adj->vertex[s].firstedge=q; } } void DisplayGraph(AdjList *adj) { int n=adj->VexNum;//頂點(diǎn)個(gè)數(shù),后面要遍歷每一個(gè)點(diǎn)點(diǎn) EdgeNode *q=NULL; int i; for( i=1;i<=n;i++) { // cout<<n<<endl; q=adj->vertex[i].firstedge; if(q==NULL)//表示頭結(jié)點(diǎn)后面沒有跟其他結(jié)點(diǎn) { cout<<"沒用從"<<adj->vertex[i].data<<"出發(fā)的節(jié)點(diǎn)"<<endl; } else { cout<<"從結(jié)點(diǎn)"<<adj->vertex[i].data<<"出發(fā)的邊有"<<endl; while(q!=NULL) { // cout<<adj->vertex[i].data<<"->"<<q->data<<endl; cout<<adj->vertex[i].data<<"->"<<adj->vertex[q->adjvex].data<<endl; q=q->next; } } } } void main() { int n; AdjList *adj=(AdjList *)malloc(sizeof(AdjList)); CreateGraph(adj,&n); DisplayGraph(adj); // cout<<"hello world!"<<endl; }?
輸出結(jié)果為:
輸入頂點(diǎn)數(shù)和邊數(shù) 6 6 輸入第1個(gè)結(jié)點(diǎn)的頂點(diǎn)名稱 a 輸入第2個(gè)結(jié)點(diǎn)的頂點(diǎn)名稱 b 輸入第3個(gè)結(jié)點(diǎn)的頂點(diǎn)名稱 c 輸入第4個(gè)結(jié)點(diǎn)的頂點(diǎn)名稱 d 輸入第5個(gè)結(jié)點(diǎn)的頂點(diǎn)名稱 e 輸入第6個(gè)結(jié)點(diǎn)的頂點(diǎn)名稱 f 輸入第1條邊的起點(diǎn)和終點(diǎn) 1 3 輸入第2條邊的起點(diǎn)和終點(diǎn) 2 4 輸入第3條邊的起點(diǎn)和終點(diǎn) 2 1 輸入第4條邊的起點(diǎn)和終點(diǎn) 4 3 輸入第5條邊的起點(diǎn)和終點(diǎn) 3 6 輸入第6條邊的起點(diǎn)和終點(diǎn) 3 5 從結(jié)點(diǎn)a出發(fā)的邊有 a->c 從結(jié)點(diǎn)b出發(fā)的邊有 b->a b->d 從結(jié)點(diǎn)c出發(fā)的邊有 c->e c->f 從結(jié)點(diǎn)d出發(fā)的邊有 d->c 沒用從e出發(fā)的節(jié)點(diǎn) 沒用從f出發(fā)的節(jié)點(diǎn)?
3.代碼實(shí)例2(ps:補(bǔ)充于2011-6-14)
? ? ? 總體而言,鄰接表表示法中主要含有兩種結(jié)點(diǎn),分別是頭結(jié)點(diǎn)和表結(jié)點(diǎn)(也叫做邊結(jié)點(diǎn)),在頭結(jié)點(diǎn)(s)到表結(jié)點(diǎn)(d)之間存在著一條邊。如果頭結(jié)點(diǎn)后面有多個(gè)表結(jié)點(diǎn),即s->d1->d2,則表示存在著兩條邊,分別是e(s,d1)和e(s,d2)。鄰接表表示法中,頭結(jié)點(diǎn)的數(shù)量是固定的,就是圖中的頂點(diǎn)數(shù)量V,表結(jié)點(diǎn)的數(shù)量由邊的數(shù)量來決定。如果是有向圖,表結(jié)點(diǎn)的數(shù)量=邊的數(shù)量;如果是無向圖,則表結(jié)點(diǎn)的數(shù)量=邊的數(shù)量*2。
? ? ? 在構(gòu)造圖的時(shí)候,如果一個(gè)頭結(jié)點(diǎn)后面有多個(gè)表結(jié)點(diǎn),那么表結(jié)點(diǎn)按次序添加在頭結(jié)點(diǎn)后面。比如原先有結(jié)構(gòu)s->d1->d2,現(xiàn)在需要添加表結(jié)點(diǎn)d3,那么需要打斷s->d1的指針,讓d3指向d1,s指向d3。即s->d3->d1->d2。
#include<iostream> #include<stdlib.h> using namespace std; #define MAX_VERTEX_NUM 50//定義圖的最大頂點(diǎn)數(shù) typedef char VertexData;//頂點(diǎn)名稱是字符型。 typedef struct EdgeNode//表結(jié)點(diǎn) { int adjvex;//鄰接點(diǎn)域 VertexData data; EdgeNode *next;//表結(jié)點(diǎn)所對(duì)應(yīng)的下一個(gè)表結(jié)點(diǎn) } EdgeNode; typedef struct VertexNode//頭結(jié)點(diǎn) { VertexData data; EdgeNode *firstedge;//頭結(jié)點(diǎn)所對(duì)應(yīng)的第一個(gè)表結(jié)點(diǎn) }VertexNode; typedef struct AdjList//圖的數(shù)據(jù)結(jié)構(gòu) { int VexNum,ArcNum;//定義圖的頂點(diǎn)數(shù)和邊數(shù) VertexNode vertex[MAX_VERTEX_NUM];//定義頭結(jié)點(diǎn)數(shù)組。 }AdjList; void CreateGraph(AdjList *adj) { int s,d; int i; cout<<"輸入頂點(diǎn)數(shù)和邊數(shù)"<<endl; cin>>adj->VexNum>>adj->ArcNum;//輸入圖的頂點(diǎn)數(shù)和邊數(shù)。 EdgeNode *q=NULL;//定義表結(jié)點(diǎn) //初始化表頭結(jié)點(diǎn) cout<<"輸入"<<adj->VexNum<<"個(gè)頭結(jié)點(diǎn)的名稱"<<endl; for(i=1;i<=adj->VexNum;i++) { //adj->vertex[i]是頭結(jié)點(diǎn)數(shù)組 cin>>adj->vertex[i].data;//頂點(diǎn)名稱,是一個(gè)字符 adj->vertex[i].firstedge=NULL;//初始狀態(tài)下頭結(jié)點(diǎn)后面不跟表結(jié)點(diǎn),因此firstedge=null } //在初始化頭結(jié)點(diǎn)以后,就需要開始將表結(jié)點(diǎn)添加到頭結(jié)點(diǎn)后面去。 cout<<"輸入"<<adj->ArcNum<<"條邊的起點(diǎn)和終點(diǎn)"<<endl; for(i=1;i<=adj->ArcNum;i++) { cin>>s>>d;//輸入邊的起始和終止,起始s就是頭結(jié)點(diǎn)位置,終止d就是表結(jié)點(diǎn)位置 q=(EdgeNode *)malloc(sizeof(EdgeNode));//創(chuàng)建一個(gè)表結(jié)點(diǎn),為其分配空間 if(q==NULL) return; /* 如果原來的鏈表是s->a->b-c>,現(xiàn)在要加入一個(gè)表結(jié)點(diǎn)q,那么加入以后就變成了s->q->a->b->c 因此: 1.q所指向的應(yīng)該是當(dāng)前s所指向的元素。 2.q的鄰接點(diǎn)域是d 3.s的指針指向q 操作如以下三行代碼 */ q->adjvex=d;//表結(jié)點(diǎn)的鄰接點(diǎn)域是d q->next=adj->vertex[s].firstedge;//新加入的節(jié)點(diǎn)都是在頭結(jié)點(diǎn)之后,原來在頭結(jié)點(diǎn)之后的節(jié)點(diǎn)要后移。 adj->vertex[s].firstedge=q; } } void DisplayGraph(AdjList *adj) { int n=adj->VexNum;//頂點(diǎn)個(gè)數(shù),后面要遍歷每一個(gè)點(diǎn)點(diǎn) EdgeNode *q=NULL; int i; for( i=1;i<=adj->VexNum;i++) { // cout<<n<<endl; q=adj->vertex[i].firstedge;//q為頭結(jié)點(diǎn)i所指向的表結(jié)點(diǎn),i->q之間存在邊 if(q==NULL)//表示頭結(jié)點(diǎn)后面沒有跟其他結(jié)點(diǎn) { cout<<"沒用從"<<adj->vertex[i].data<<"出發(fā)的節(jié)點(diǎn)"<<endl; } else { cout<<"從結(jié)點(diǎn)"<<adj->vertex[i].data<<"出發(fā)的邊有"<<endl; while(q!=NULL) { // cout<<adj->vertex[i].data<<"->"<<q->data<<endl; cout<<adj->vertex[i].data<<"->"<<adj->vertex[q->adjvex].data<<endl; q=q->next;//鏈表往后跳 } } } } void main() { int n; AdjList *adj=(AdjList *)malloc(sizeof(AdjList)); CreateGraph(adj); DisplayGraph(adj); system("pause"); } /* 輸入頂點(diǎn)數(shù)和邊數(shù) 6 6 輸入6個(gè)頭結(jié)點(diǎn)的名稱 a b c d e f 輸入6條邊的起點(diǎn)和終點(diǎn) 1 3 2 4 2 1 4 3 3 6 3 5 從結(jié)點(diǎn)a出發(fā)的邊有 a->c 從結(jié)點(diǎn)b出發(fā)的邊有 b->a b->d 從結(jié)點(diǎn)c出發(fā)的邊有 c->e c->f 從結(jié)點(diǎn)d出發(fā)的邊有 d->c 沒用從e出發(fā)的節(jié)點(diǎn) 沒用從f出發(fā)的節(jié)點(diǎn) 請(qǐng)按任意鍵繼續(xù). . . */?
?
轉(zhuǎn)載于:https://www.cnblogs.com/xwdreamer/archive/2011/04/15/2297028.html
總結(jié)
以上是生活随笔為你收集整理的有向图的邻接表表示法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用AsyncCtp实现一个简单的Echo
- 下一篇: 可自动定时切换的选项卡/滑动门导航代码