一:總結圖的基本概念:
1.圖分爲有向圖(入度和出度)和無向圖(最大邊數n(n-1)/2);
2.圖的存儲結構:
1)關聯矩陣(表示了圖的結構,即圖中各結點的後件關係):表示各個結點的前件與後件關係,矩陣R(i,j)=1,表示結點i是結點j的前件,矩陣R(i,j)=0,表示結點i不是結點j的前件,無向圖的關聯矩陣是對稱矩陣,且對角線上的元素均爲0.有向圖的不一定是對稱矩陣且對角線不一定爲0;
2)求值矩陣(表示了圖中每兩個結點之間的求值函數):在求值矩陣V中,一般用-1表示兩個結點無直接連通;
3)鄰接表(存儲結構也稱“順序--索引---鏈接”存儲結構):首先,用一個順序存儲空間來存儲圖中各個結點信息。其次,對應圖中每個結點構造一個單鏈表,該單鏈表的頭指針即爲順序空間中的對應存儲結點的指針域。
二:圖鄰接表類
1.圖鄰接表類//文件名 :Link_GP.h
#include "sq_Queue.h"
#include <iostream>
#include <fstream>
using namespace std;
template <class T1>
struct node
{
int num;
T1 val;
node * next;
};
template <class T1,class T2>
struct gpnode
{
T2 data;
node<T1> *link;
};
//定義圖鄰接表類
template <class T1,class T2>
class Link_GP
{
private:
int nn; //圖中結點個數
gpnode<T1,T2> *gp;//圖鄰接表中順序存儲空間首地址
public:
Link_GP(){gp=NULL;return;}//圖鄰接表初始化
void creat_Link_GP(int,T2[]);//由鍵盤輸入生成圖鄰接表
void creat_Link_GP(int,T2[],char *);//由文件數據生成圖鄰接表
void prt_Link_GP();//輸出圖鄰接表
void dfs_Link_GP();//縱向優先搜索法遍歷圖
void bfs_Link_GP();//橫向優先搜索法遍歷圖
void short_Link_GP(int);//求指定結點到其餘各結點的最短距離
void short_path_Link_GP(int);//求指定結點到其餘各結點的最短距離與路徑
};
//由鍵盤輸入生成圖鄰接表
template <class T1,class T2>
void Link_GP<T1,T2>::creat_Link_GP(int n,T2 d[])
{
node<T1> *p;
nn=n; //圖中結點個數
int k,m;
T1 v;
gp=new gpnode<T1,T2>[nn];//申請圖鄰接表中順序存儲空間
for(k=0;k<nn;k++) //依次對圖中的每個結點建立鏈接所有後件的單鏈表
{
(gp+k)->data=d[k];//置順序存儲空間的結點值
(gp+k)->Link=NULL;//置順序存儲空間結點的指針域爲空
cout<<"請輸入圖中第"<<k<<"個結點的後件信息:"<<endl;
cin>>m>>v; //輸入後件信息
while(m>=0)
{
p=new node<T1>; //申請單鏈表結點
p->num=m;p->val=v;
p->next=(gp+k)->link;//新結點指針指向原頭結點
(gp+k)->link=p;//將新結點鏈接到單鏈錶鏈頭
cin>>m>>v;
}
}
return;
}
//由文件數據生成圖鄰接表
template<class T1,class T2>
void Link_GP<T1,T2>::creat_Link_GP(int n,T2 d[],char * filename)
{
node<T1> *p;
int k,m;
nn=n;
T1 v;
ifstream infile(filename,ios::in);//打開文件
gp=new gpnode<T1,T2>[nn];
for(k=0;k<nn;k++) //依次對圖中的每個結點建立鏈接所有後件的單鏈表
{
(gp+k)->data=d[k];//置順序存儲空間的結點值
(gp+k)->link=NULL;//置順序存儲空間結點的指針域爲空
infile>>m>>v; //輸入後件信息
while(m>=0)
{
p=new node<T1>; //申請單鏈表結點
p->num=m;p->val=v;
p->next=(gp+k)->link;//新結點指針指向原頭結點
(gp+k)->link=p;//將新結點鏈接到單鏈錶鏈頭
infile>>m>>v;
}
}
return;
}
template<class T1,class T2>
void Link_GP<T1,T2>::prt_Link_GP()
{
node<T1> *q;
int k;
for(k=0;k<nn;k++)
{
cout<<(gp+k)->data;
q=(gp+k)->link;
while(q!=NULL)
{
cout<<"---->";
cout<<q->num<<","<<q->val;
q=q->next;
}
cout<<endl;
}
return;
}
//縱向優先搜索法遍歷圖
template<class T1,class T2>
void Link_GP<T1,T2>::dfs_Link_GP()
{
int k,*mark;
mark=new int[nn];//申請標誌數組空間
for(k=0;k<nn;k++)
mark[k]=0;
for(k=0;k<nn;k++)
if(mark[k]==0) dfs(gp,k,mark);
cout<<endl;
delete mark;
return;
}
template<class T1,class T2>
static dfs(gpnode<T1,T2> *q,int k,int *mark)
{
node<T1> *p;
cout<<(q+k)->data<<" ";//輸出當前圖結點值
mark[k]=1; //記錄當前結點已查訪標誌
p=(q+k)->link;
while(p!=NULL)
{
if(mark[p->num-1]==0)//該後件結點未查訪過
dfs(q,p->num-1,mark);
p=p->next;//下一個後件結點
}
return 0;
}
//橫向優先搜索法遍歷圖
template<class T1,class T2>
void Link_GP<T1,T2>::bfs_Link_GP()
{
int *mark,k;
sq_Queue<int> q(nn); //建立循環隊列空間並初始化
node<T1> *p;
mark=new int[nn]; //申請標誌數組空間
for(k=0;k<nn;k++)
mark[k]=0;
for(k=0;k<nn;k++) //對每個圖結點橫向優先搜索
{
if(mark[k]==0) //當前未查訪過
{
mark[k]=1; //記錄當前結點已經查訪過
cout<<gp->data<<" "; //輸出當前值
q.ins_sq_Queue(k); //當前結點編號入隊
while(q.flag_sq_Queue())//隊列不空
{
k=q.del_sq_Queue(); //從隊列中退出一個結點作爲當前結點
p=(gp+k)->link;// 所有後件結點鏈表指針
while(p!=NULL) //還有後件
{
k=p->num-1;
if(mark[k]==0)
{
cout<<(gp+k)->data<<" ";
mark[k]=1;
q.ins_sq_Queue(k);
}
p=p->next; //下一個後件
}
}
}
}
cout<<endl;
delete mark;
return;
}
//求指定結點到其餘各結點的最短距離
template <class T1>
struct pathnode
{
T1 path; //最短距離
node<T1> *elink; //路徑單鏈表指針
};
template <class T1,class T2>
void Link_GP<T1,T2>::short_Link_GP(int m)
{
int *mark,k,j,h;
pathnode<T1> *e;
node<T1> *p,*pp;
sq_Queue<int> q(nn);
e=new pathnode<T1>[nn];
mark=new int[nn];
for(k=0;k<nn;k++)
mark[k]=0;
for(k=0;k<nn;k++)
{
(e+k)->path=-1;(e+k)->elink=NULL;
}
(e+m-1)->path=0;
q.ins_sq_Queue(m);
mark[m-1]=1;
while(q.flag_sq_Queue())
{
k=q.del_sq_Queue();
p=(gp+k-1)->link;
while(p!=NULL)
{
j=p->num;
h=((e+k-1)->path)+p->val;
if(((e+j-1)->path==-1)||((e+j-1)->path>h))
{
(e+j-1)->path=h;
pp=(e+j-1)->elink;
if(pp==NULL)
pp=new node<T1>;
pp->num=j;pp->val=p->val;
pp->next=(e+k-1)->elink;(e+j-1)->elink=pp;
if(mark[j-1]==0)
{
mark[j-1]=1;
q.ins_sq_Queue(j);
}
}
p=p->next;
}
}
cout<<"k "<<"PATH "<<endl;
for(k=0;k<nn;k++) //輸出各結點到起始結點的最短距離與路徑
{
cout<<k+1<<" "<<(e+k)->path<<" ";//輸出結點編號與最短距離
/*
p=(e+k)->elink;
while(p!=NULL) //輸出路徑
{
cout<<"--->";
cout<<p->num<<","<<p->val;
p=p->next;
}
cout<<endl;
}*/
cout<<endl;
}
delete mark;
delete e;
return;
}
//求指定結點到其餘各結點的最短距離與路徑
//定義最短距離與路徑順序存儲空間結點類型
/*
template <class T1>
struct pathnode
{
T1 path; //最短距離
node<T1> *elink; //路徑單鏈表指針
};*/
template <class T1,class T2>
void Link_GP<T1,T2>::short_path_Link_GP(int m)
{
int *mark,k,j,h;
pathnode<T1> *e;
node<T1> *p,*pp;
sq_Queue<int> q(nn);
e=new pathnode<T1>[nn];
mark=new int[nn];
for(k=0;k<nn;k++)
mark[k]=0;
for(k=0;k<nn;k++)
{
(e+k)->path=-1;(e+k)->elink=NULL;
}
(e+m-1)->path=0;
q.ins_sq_Queue(m);
mark[m-1]=1;
while(q.flag_sq_Queue())
{
k=q.del_sq_Queue();
p=(gp+k-1)->link;
while(p!=NULL)
{
j=p->num;
h=((e+k-1)->path)+p->val;
if(((e+j-1)->path==-1)||((e+j-1)->path>h))
{
(e+j-1)->path=h;
pp=(e+j-1)->elink;
if(pp==NULL)
pp=new node<T1>;
pp->num=j;pp->val=p->val;
pp->next=(e+k-1)->elink;(e+j-1)->elink=pp;
if(mark[j-1]==0)
{
mark[j-1]=1;
q.ins_sq_Queue(j);
}
}
p=p->next;
}
}
cout<<"k "<<"PATH "<<"ELINK "<<endl;
for(k=0;k<nn;k++) //輸出各結點到起始結點的最短距離與路徑
{
cout<<k+1<<" "<<(e+k)->path<<" ";//輸出結點編號與最短距離
p=(e+k)->elink;
while(p!=NULL) //輸出路徑
{
cout<<"--->";
cout<<p->num<<","<<p->val;
p=p->next;
}
cout<<endl;
}
delete mark;
delete e;
return;
}
2.具體應用:
#include "Link_GP.h"
int main()
{
char d[8]={'A','B','C','D','E','F','G','H'};
Link_GP<int,char> g;
g.creat_Link_GP(8,d,"f1.txt");
cout<<"圖g鄰接表:"<<endl;
g.prt_Link_GP();
cout<<"縱向優先搜索法遍歷圖:"<<endl;
g.dfs_Link_GP();
cout<<"橫向優先搜索法遍歷圖:"<<endl;
g.bfs_Link_GP();
cout<<"第3個結點到其餘各結點的最短距離:"<<endl;
g.short_Link_GP(3);
cout<<"第3個結點到其餘結點的最短距離與路徑:"<<endl;
g.short_path_Link_GP(3);
return 0;
}
3.實驗結果
4.附件:sq_Queue.h
#include <iostream>
using namespace std;
template <class T>
class sq_Queue
{
private:
int mm;//存儲空間容量
int front;
int rear;
int s;//標誌
T * q;
public:
sq_Queue(int);
void prt_sq_Queue();
int flag_sq_Queue();
void ins_sq_Queue(T);
T del_sq_Queue();
};
template <class T>
sq_Queue<T>::sq_Queue(int m)
{
mm=m;
q=new T[mm];
front=mm;
rear=mm;
s=0;
return;
}
template <class T>
void sq_Queue<T>::prt_sq_Queue()
{
int i;
cout<<"front="<<front<<endl;
cout<<"rear="<<rear<<endl;
if(s==0)
{
cout<<"隊列空"<<endl;
return;
}
i=front;
do
{
i=i+1;
if(i==mm+1)
i=1;
cout<<q[i-1]<<endl;
} while (i!=rear);
return;
}
template <class T>
int sq_Queue<T>::flag_sq_Queue()
{
if((s==1)&&(rear==front))
{
cout<<"隊列滿"<<endl;
return (-1);
}
if(s==0)
{
cout<<"隊列空"<<endl;
return 0;
}
return 1;
}
template <class T>
void sq_Queue<T>::ins_sq_Queue(T b)
{
if((s==1)&&(rear==front))
{
cout<<"Queue overflow"<<endl;
return;
}
rear=rear+1;
if(rear==mm+1)rear=1;
q[rear-1]=b;
s=1;
return;
}
template <class T>
T sq_Queue<T>::del_sq_Queue()
{
T y;
if(s==0)
{
cout<<"queue is empty"<<endl;
return (0);
}
front=front+1;
if(front==mm+1)//特別要注意等號“==”而不是“=“
front=1;
y=q[front-1];
if(rear==front)
s=0;
return y;
}