一:总结图的基本概念:
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;
}