图邻接表类(图的遍历方法,最短距离及路径)

来源:互联网 发布:js记录页面刷新次数 编辑:程序博客网 时间:2024/06/01 11:50

一:总结图的基本概念:

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;}