實驗 6:圖的實驗 1 -有向圖的鄰接表儲存實現
一、實驗目的
1、 熟練理解圖的相關概念;
2、 掌握圖的鄰接矩陣的儲存方法的實現;
3、 學會圖的遍歷演算法
二、實驗內容
1、自己確定一個簡單無向圖(頂點數、和相關結點資訊)利用鄰接矩陣來實現儲存。實現圖的構造,並完成:
1) 用深度優先和廣度優秀兩種演算法對圖進行遍歷,輸出頂點序列資料;
2) 以合理的格式,輸出各個頂點的鄰接點;
2、試設計一個程式,對一個有向簡單圖,完成上題同樣的任務。
三、設計與編碼
1.本實驗用到的理論知識
(1)鄰接表是順序儲存結構與鏈式儲存結構相結合的儲存方法,類似於樹的孩子連結串列表示法;
(2)在鄰接表中涉及入度與出度,鄰接與(到)的概念;
(3)需要用結構體定義頂點表結點和邊表結點。
2.演算法與設計
(1)定義一個ALGraph類
class ALGraph
{
public:
ALGraph(char a[],int n,int e); //建構函式
~ALGraph(); //解構函式
void DFSTraverse(int v); //深度優先遍歷圖
void BFSTraverse(int v); //廣度優先遍歷
void Print(char a [],int length);
private:
VertexNode adjlist[MaxSize]; //存放頂點表的陣列
int vertexNum,arcNum; //圖的頂點數和邊數
};
3.程式碼
#include<iostream.h>
const int MaxSize=10; //圖最大的頂點數
int visited[MaxSize]={0}; //標誌陣列的visited[]為全域性變數
struct ArcNode //定義邊表結點
{
ArcNode *next;
};
struct VertexNode //定義頂點表結點
{
char vertex;
ArcNode *firstedge;
};
class ALGraph
{
public:
ALGraph(char a[],int n,int e); //建構函式
~ALGraph(); //解構函式
void DFSTraverse(int v); //深度優先遍歷圖
void BFSTraverse(int v); //廣度優先遍歷
void Print(char a [],int length);
private:
VertexNode adjlist[MaxSize]; //存放頂點表的陣列
int vertexNum,arcNum; //圖的頂點數和邊數
};
ALGraph::ALGraph(char a[],int n,int e)
{
ArcNode *s;
int i,j,k;
vertexNum=n;
arcNum=e;
for(i=0;i<vertexNum;i++) //儲存頂點資訊,初始化頂點表
{
adjlist[i].vertex=a[i];
adjlist[i].firstedge=NULL;
}
for(k=0;k<arcNum;k++) //依次輸入每一條邊
{
cout<<"請輸入邊的兩個頂點的序號:"<<endl;
cin>>i>>j; //輸入邊所依據的兩個頂點的編號
s=new ArcNode; //生成一個邊表結點s
s->adjvex=j;
s->next=adjlist[i].firstedge; //將結點s插入到第i個邊表的表頭
adjlist[i].firstedge=s;
}
}
ALGraph::~ALGraph()
{
ArcNode *p=NULL;
for(int i=0;i<vertexNum;i++)
{
p=adjlist[i].firstedge;
while(p!=NULL) //刪除第i條邊
{
adjlist[i].firstedge=p->next;
delete p; //釋放結點空間
p=adjlist[i].firstedge;
}
}
}
void ALGraph::DFSTraverse(int v) //深度優先遍歷圖
{
ArcNode *p=NULL;
int j;
cout<<adjlist[v].vertex;
visited[v]=1;
p=adjlist[v].firstedge; //工作指標p指向頂點v的邊表
while(p!=NULL) //依次搜尋頂點v的鄰接點j
{
j=p->adjvex;
if(visited[j]==0) DFSTraverse(j);
p=p->next;
}
}
void ALGraph::BFSTraverse(int v) //廣度優先遍歷
{
int Q[MaxSize]; //假設佇列採用順序儲存
int front=-1,rear=-1; //初始化佇列
ArcNode *p=NULL;
cout<<adjlist[v].vertex;
visited[v]=1;
Q[++rear]=v; //被訪問頂點入隊
while(front!=rear) //當佇列非空時
{
v=Q[++front];
p=adjlist[v].firstedge; //工作指標p指向頂點v的邊表
while(p!=NULL)
{
int j=p->adjvex; //j是頂點v的鄰接點
if(visited[j]==0)
{
cout<<adjlist[j].vertex;
visited[j]=1;
Q[++rear]=j;
}
p=p->next;
}
}
}
void ALGraph::Print(char a[],int length) //輸出鄰接點資訊
{
for(int i=0;i<length;i++)
{
cout<<a[i]<<"->";
if(adjlist[i].firstedge!=NULL) //當頂點a[i]的指標域firstedge非空時,說明a[i]有鄰接點
cout<<a[adjlist[i].firstedge->adjvex]; //輸出a[i]的鄰接點
else break;
cout<<endl;
}
}
int main()
{
char ch[]={'A','B','C','D','E'}; //char型的頂點資訊
ALGraph ALG(ch,5,7); //呼叫建構函式
for(int i=0;i<MaxSize;i++) //初始化圖中所有頂點均未被訪問
visited[i]=0;
cout<<"深度優先遍歷序列是:";
ALG.DFSTraverse(0); //從頂點0出發進行深度優先遍歷
cout<<endl;
for(i=0;i<MaxSize;i++) //初始化圖中所有頂點均未被訪問
visited[i]=0;
cout<<"廣度優先遍歷序列是:";
ALG.BFSTraverse(0); //從頂點0出發進行廣度優先遍歷
cout<<endl;
cout<<"各頂點之間的鄰接關係:"<<endl;
ALG.Print(ch,5); //輸出鄰接點資訊
cout<<endl;
return 0;
}
四、執行結果
五、總結與心得
有一個疑問:為什麼要用結構體來定義邊表結點和頂點表結點而不直接在類內定義?