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

一:总结图的基本概念:

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

 

    原文作者:数据结构之图
    原文地址: https://blog.csdn.net/xumin07061133/article/details/8039316
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞