数据结构实验9:图的相关操作

版权声明:分享、借鉴或使用刁肥宅的劳动成果请务必注明出处!刁肥宅保留追究剽窃者的一切权利! https://blog.csdn.net/u25th_engineer/article/details/85856940

                                               

目录

                                                 实验9

8.1 实验目的

8.2 实验任务

8.3 实验说明

1. 数据文件格式设计

2. 从数据文件创建邻接矩阵表示的图

3. 从数据文件创建邻接表表示的图

4. 图的销毁

8.4 运行截图

8.5 附源代码

扫描二维码关注公众号,回复: 6072131 查看本文章

严正声明


                                               实验9

                                                                            姓名: 学号: 班级:

8.1 实验目的

(1) 掌握图的基本概念。

(2) 掌握图的存储结构的设计与实现,基本运算的实现。

(3) 熟练掌握图的两种遍历算法、遍历生成树及遍历算法的应用。

8.2 实验任务

分别设计图(网)的邻接矩阵、邻接表存储结构,编写算法实现下列问题的求解。、

数据要求:可利用8.3中的数据,也可自行编写数据。

1.打印出图(网)的两种遍历序列。

2.求给定图中的边(或弧)的数目。

3.对给定的图G及出发点v0,设计算法从V0出发深度优先遍历图G,并构造出相应的生成树或生成森林。

4.对给定的图G及出发点v0,设计算法从V0出发广度优先遍历图G,并构造出相应的生成树或生成森林。

8.3 实验说明

这里介绍一种从文本文件读入图的数据创建图的方法,这样我们可以按照指定的格式,先从容地准备好数据,然后由程序自动读入数据来创建图。

createGrpAdjMatrix.h,文件创建邻接矩阵表示的图。

createGrpAdjLinkedList.h,文件创建邻接表表示的图。

(以下给出的图的创建方法仅供参考,实验者可自行设计其它创建方法)

1. 数据文件格式设计

这里数据用文本文件保存,文件扩展名可自行指定,比如g8.grp,只要数据按文本文件格式读写即可。下面给出一种数据文件格式,其实读者可以自行设计图的数据文件格式。

①标识行1:Graph

标识这是一个图的数据文件,这一行也可以不要。

②标识行2:UDG、或UDN、或DG、或DN

这一行用来标识此图是无向图(UDG)、无向网(UDN)、有向图(DG)、还是有向网(DN)。

③顶点行

这一行将图中所有顶点列出,顶点之间用空格进行分割。这些顶点数据读出后存放到图的顶点数组中。

例如,图6-21(a)所示的图的顶点行数据为:a b c d。

图的各种算法都是用顶点的编号来引用顶点的,所以这一行顶点的排列顺序是很重要的,顶点的排列顺序决定了顶点的编号。比如上例中,顶点a、b、c、d对应的编号就为1、2、3、4。

④边数据行

一条边一行,边的2个顶点之间用空格分割。如果是网,每一行再加边的权值,也以空格分割。如果是无向图和无向网,每条边会重复一次。

例如图6-18(a)无向图的边的数据为:

a b

a c

a d

b a

b c

c a

c b

c d

d a

d c

图6-21(a)无向网边的数据为:

a b 4

a c 5

a d 3

b a 4

b c 2

c a 5

c b 2

c d 6

d a 3

d c 6

⑤其它行

如果程序强大一点,还可以在文件中加注释行,允许出现空行等,当然这是非必须的。

举一个完整的图的数据文件的例子,对图6-18(a)的无向图,完整的数据文件如下:

//文件可以加注释行,注释以“//”开始

//Graph为图标志,否则判定格式不对

//标志行后,第一行为图的类型。UDG--无向图;UDN--无向网;DG--有向图;DN--有向网

//标志行后,第二行为顶点元素

//顶点行以下图的边或弧。用顶点表示,第一列为起始顶点;第二列为邻接点;在网中再增加一列表示权值。

//本图具有4个顶点5条边

//下一行为图的标识行

                     Graph

//图的类型标识,此为无向图

UDG

//顶点元素数据

a b c d

//以下为边的数据,共10行数据,表示5条边

a b

a c

a d

b a

b c

c a

c b

c d

d a

d c

文件名不妨叫做Gudg4.grp。

再举一个有向网的例子,对图1所示的有向网,完整的数据文件如下:

 

图1 一个有向网实例

//标识为图数据

                     Graph

//标识有向网

DN

//顶点数据

a b c d e f g h i j

//以下为边数据,共15条边

a b 2

a d 20

b e 1

c a 3

d c 8

d f 6

d g 4

e c 7

e h 3

f c 1

g h 1

h f 2

h j 2

i g 2

j i 1

不妨设文件名为Gdn10.grp

2. 从数据文件创建邻接矩阵表示的图

指定图的数据文件名,然后逐行读出数据并处理,自动创建邻接矩阵表示的图。本程序可以自动处理注释行和空行,程序实现如下:

//****************************文件创建图*****************************//
//* 函数功能:从文本文件创建邻接矩阵表示的图                        *//
//* 入口参数  char fileName[],文件名                               *//
//* 出口参数:Graph &G,即创建的图                                  *//
//* 返回值:bool,true创建成功;false创建失败                    *//
//* 函数名:CreateGraphFromFile(char fileName[], Graph &G)        *//
//*******************************************************************//
int CreateGraphFromFile(char fileName[], Graph &G)
{
	FILE* pFile;          //定义文件指针
	char str[1000];         //存放读出一行文本的字符串
	char strTemp[10];      //判断是否注释行
	cellType eWeight;      //边的信息,常为边的权值
	GraphKind graphType;  //图类型枚举变量
	pFile=fopen(fileName,"r");
	if(!pFile)
	{
		printf("错误:文件%s打开失败。\n",fileName);
		return false;
	}
	while(fgets(str,1000,pFile)!=NULL)
	{
		strLTrim(str);     //删除字符串左边空格,这是一个自定义的函数
		if (str[0]=='\n')    //空行,继续读取下一行
			continue;
		strncpy(strTemp,str,2);
		if(strstr(strTemp,"//")!=NULL)  //跳过注释行
			continue;
		else                       //非注释行、非空行,跳出循环
			break;
	}
    //循环结束,str中应该已经是图的标识Graph,判断标识是否正确
	if(strstr(str,"Graph")==NULL)
	{
		printf("错误:打开的文件格式错误!\n");
		fclose(pFile); //关闭文件
		return false;
	}
	//读取图的类型,跳过空行
	while(fgets(str,1000,pFile)!=NULL)
	{
		strLTrim(str);    //删除字符串左边空格,这是一个自定义函数
		if (str[0]=='\n')   //空行,继续读取下一行
			continue;
		strncpy(strTemp,str,2);
		if(strstr(strTemp,"//")!=NULL)  //注释行,跳过,继续读取下一行
			continue;		
		else                       //非空行,也非注释行,即图的类型标识
			break;
	}
    //设置图的类型
	if(strstr(str,"UDG"))
		graphType=UDG;    //无向图
	else if(strstr(str,"UDN"))
		graphType=UDN;    //无向网
	else if(strstr(str,"DG"))
		graphType=DG;     //有向图
	else if(strstr(str,"DN"))
		graphType=DN;     //有向网
	else
	{
		printf("错误:读取图的类型标记失败!\n");
		fclose(pFile);       //关闭文件
		return false;
	}
	//读取顶点行数据到str。跳过空行
	while(fgets(str,1000,pFile)!=NULL)
	{
		strLTrim(str);      //删除字符串左边空格,这是一个自定义函数
		if (str[0]=='\n')     //空行,继续读取下一行
			continue;
		strncpy(strTemp,str,2);
		if(strstr(strTemp,"//")!=NULL)  //注释行,跳过,继续读取下一行
			continue;		
		else                       //非空行,也非注释行,即图的顶点元素行
			break;
	}

    //顶点数据放入图的顶点数组	
	char* token=strtok(str," ");
	int nNum=0;	
	while(token!=NULL)
	{
		G.Data[nNum]=*token; 
      token = strtok( NULL, " ");
		nNum++;
	}
	//图的邻接矩阵初始化
	int nRow=0;    //矩阵行下标
	int nCol=0;     //矩阵列下标
	if(graphType==UDG || graphType==DG)
	{
		for(nRow=0;nRow<nNum;nRow++)
			for(nCol=0;nCol<nNum;nCol++)
				G.AdjMatrix[nRow][nCol]=0;
	}
	else
	{
		for(nRow=0;nRow<nNum;nRow++)
			for(nCol=0;nCol<nNum;nCol++)
				G.AdjMatrix[nRow][nCol]=INF;  //INF表示无穷大
	}
		//循环读取边的数据到邻接矩阵
	int edgeNum=0;         //边的数量
	elementType Nf, Ns;     //边或弧的2个相邻顶点
	while(fgets(str,1000,pFile)!=NULL)
	{
		strLTrim(str);       //删除字符串左边空格,这是一个自定义函数
		if (str[0]=='\n')      //空行,继续读取下一行
			continue;
		strncpy(strTemp,str,2);
		if(strstr(strTemp,"//")!=NULL)  //注释行,跳过,继续读取下一行
			continue;
		char* token=strtok(str," ");  //以空格为分隔符,分割一行数据,写入邻接矩阵
		if(token==NULL)         //分割为空串,失败退出
		{
			printf("错误:读取图的边数据失败!\n");
			fclose(pFile);         //关闭文件
			return false;
		}
		Nf=*token;               //获取边的第一个顶点
		token = strtok( NULL, " ");   //读取下一个子串,即第二个顶点
		if(token==NULL)          //分割为空串,失败退出
		{
			printf("错误:读取图的边数据失败!\n");
			fclose(pFile);          //关闭文件
			return false;
		}
		Ns=*token;  //获取边的第二个顶点
                 //从第一个顶点获取行号		
		for(nRow=0;nRow<nNum;nRow++)
		{
			if(G.Data[nRow]==Nf)  //从顶点列表找到第一个顶点的编号
				break;
		}
                  //从第二个顶点获取列号
		for(nCol=0;nCol<nNum;nCol++)
		{
			if(G.Data[nCol]==Ns)  //从顶点列表找到第二个顶点的编号
				break;
		}
		//如果为网,读取权值
		if(graphType==UDN || graphType==DN)
		{                //读取下一个子串,即边的附加信息,常为边的权重
			token = strtok( NULL, " ");  
			if(token==NULL)    //分割为空串,失败退出
			{
				printf("错误:读取图的边数据失败!\n");
				fclose(pFile);    //关闭文件
				return false;
			}
			eWeight=atoi(token);  //取得边的附加信息
		}
		if(graphType==UDN || graphType==DN)  
			G.AdjMatrix[nRow][nCol]=eWeight;
//如果为网,邻接矩阵中对应的边设置权值,否则置为1
		else
			G.AdjMatrix[nRow][nCol]=1;  
		edgeNum++;   //边数加1
	}
  G.VerNum=nNum;           //图的顶点数
	if(graphType==UDG || graphType==UDN)
		G.ArcNum=edgeNum / 2;  //无向图或网的边数等于统计的数字除2  
	else
		G.ArcNum=edgeNum;
	G.gKind=graphType;         //图的类型
	fclose(pFile);               //关闭文件
	return true;
}

3. 从数据文件创建邻接表表示的图

程序实现如下:

//****************************文件创建图*****************************//
//* 函数功能:从文本文件创建邻接表表示的图                          *//
//* 入口参数  char fileName[],文件名                               *//
//* 出口参数:Graph &G,即创建的图                                  *//
//* 返回值:bool,true创建成功;false创建失败                    *//
//* 函数名:CreateGraphFromFile(char fileName[], Graph &G)        *//
//* 备注:本函数使用的数据文件格式以边(顶点对)为基本数据          *//
//*******************************************************************//
int CreateGraphFromFile(char fileName[], Graph &G)
{
	FILE* pFile;         //定义文件指针
	char str[1000];        //存放读出一行文本的字符串
	char strTemp[10];      //判断是否注释行
	char* ss; 
int i=0, j=0;
	int edgeNum=0;        //边的数量
	eInfoType eWeight;     //边的信息,常为边的权值
	GraphKind graphType;  //图类型枚举变量
	pFile=fopen(fileName,"r");
	if(!pFile)
	{
		printf("错误:文件%s打开失败。\n",fileName);
		return false;
	}
		while(fgets(str,1000,pFile)!=NULL)  //跳过空行和注释行
	{
		strLTrim(str);     //删除字符串左边空格,这是一个自定义函数
		if (str[0]=='\n')    //空行,继续读取下一行
			continue;
		strncpy(strTemp,str,2);
		if(strstr(strTemp,"//")!=NULL)    //跳过注释行
			continue;
		else                          //非注释行、非空行,跳出循环
			break;
	}
  //循环结束,str中应该已经是图的标识Graph,判断标识是否正确
	if(strstr(str,"Graph")==NULL)
	{
		printf("错误:打开的文件格式错误!\n");
		fclose(pFile);                //关闭文件
		return false;
	}
	//读取图的类型,跳过空行及注释行
	while(fgets(str,1000,pFile)!=NULL)
	{
		strLTrim(str);     //删除字符串左边空格,这是一个自定义函数
		if (str[0]=='\n')    //空行,继续读取下一行
			continue;
		strncpy(strTemp,str,2);
		if(strstr(strTemp,"//")!=NULL)  //注释行,跳过,继续读取下一行
			continue;		
		else                       //非空行,也非注释行,即图的类型标识
			break;
	}
  //设置图的类型
	if(strstr(str,"UDG"))
		graphType=UDG;    //无向图
	else if(strstr(str,"UDN"))
		graphType=UDN;    //无向网
	else if(strstr(str,"DG"))
		graphType=DG;     //有向图
	else if(strstr(str,"DN"))
		graphType=DN;     //有向网
	else
	{
		printf("错误:读取图的类型标记失败!\n");
		fclose(pFile);       //关闭文件
		return false;
	}
	//读取顶点数据到str。跳过空行
	while(fgets(str,1000,pFile)!=NULL)
	{
		strLTrim(str);     //删除字符串左边空格,这是一个自定义函数
		if (str[0]=='\n')    //空行,继续读取下一行
			continue;
		strncpy(strTemp,str,2);
		if(strstr(strTemp,"//")!=NULL)  //注释行,跳过,继续读取下一行
			continue;		
		else                       //非空行,也非注释行,即图的顶点元素行
			break;
	}
	//顶点数据放入图的顶点数组		
	char* token=strtok(str," ");
	int nNum=0;	
	while(token!=NULL)
	{
		G.VerList[nNum].data=*token;
		G.VerList[nNum].firstEdge=NULL;
token = strtok( NULL, " ");
		nNum++;
	}
	//循环读取边(顶点对)数据
	int nRow=0;          //矩阵行下标
	int nCol=0;           //矩阵列下标
	EdgeNode* eR;       //边链表尾指针
	EdgeNode* p;    
	elementType Nf, Ns;   //边或弧的2个相邻顶点
	while(fgets(str,1000,pFile)!=NULL)
	{
		strLTrim(str);     //删除字符串左边空格,这是一个自定义函数
		if (str[0]=='\n')    //空行,继续读取下一行
			continue;
		strncpy(strTemp,str,2);
		if(strstr(strTemp,"//")!=NULL)  //注释行,跳过,继续读取下一行
			continue;
		char* token=strtok(str," ");     //以空格为分隔符,分割一行数据
		if(token==NULL)            //分割为空串,失败退出
		{
			printf("错误:读取图的边数据失败!\n");
			fclose(pFile);            //关闭文件
			return false;
		}
		Nf=*token;                //获取边的第一个顶点
		token = strtok( NULL, " ");   //读取下一个子串,即第二个顶点
		if(token==NULL)          //分割为空串,失败退出
		{
			printf("错误:读取图的边数据失败!\n");
			fclose(pFile);          //关闭文件
			return false;
		}
		Ns=*token;    //获取边的第二个顶点
                   //从第一个顶点获取行号
		for(nRow=0;nRow<nNum;nRow++)
		{
			if(G.VerList[nRow].data==Nf)  //从顶点列表找到第一个顶点的编号
				break;
		}
                    //从第二个顶点获取列号
		for(nCol=0;nCol<nNum;nCol++)
		{
			if(G.VerList[nCol].data==Ns)  //从顶点列表找到第二个顶点的编号
				break;
		}
		//如果为网,读取权值
		if(graphType==UDN || graphType==DN)
		{            //读取下一个子串,即边的附加信息,常为边的权重
			token = strtok( NULL, " ");  
			if(token==NULL)    //分割为空串,失败退出
			{
				printf("错误:读取图的边数据失败!\n");
				fclose(pFile);    //关闭文件
				return false;
			}
			eWeight=atoi(token);  //取得边的附加信息,即权值
		}
		eR=G.VerList[nRow].firstEdge;
		while(eR!=NULL && eR->next!=NULL)
		{
			eR=eR->next;        //后移边链表指针,直至尾节点
		}
		p=new EdgeNode;        //申请一个边链表结点
		p->adjVer=nCol+1;       //顶点的编号,从1开始
	    //边的附加信息(权值),对有权图保存权值,无权图为1
if(graphType==UDN || graphType==DN) 
			p->eInfo=eWeight;
	    else
			p->eInfo=1; 
		p->next=NULL;
		if(G.VerList[nRow].firstEdge==NULL)
		{
			G.VerList[nRow].firstEdge=p;
			eR=p;
		}
		else
		{
			eR->next=p;
			eR=p;       //新的尾指针				
		}				
		edgeNum++;     //边数加1
	}
	G.VerNum=nNum;    //图的顶点数
	if(graphType==UDG || graphType==UDN)
		G.ArcNum=edgeNum / 2;   //无向图或网的边数等于统计的数字除2  
	else
		G.ArcNum=edgeNum;
	G.gKind=graphType;           //图的类型
	fclose(pFile);                 //关闭文件
	return true;
}

4. 图的销毁

以邻接矩阵为存储结构的图,因为使用矩阵存储图的数据,不存在销毁(释放内存)问题。但是以邻接表为存储结构的图,由于在创建图的过程中使用malloc()函数或new操作符动态申请了内存,当这个图不再需要时,必须手工释放动态申请的内存,否则造成内存泄漏。下面给出一个销毁邻接表表示的图的程序。

void DestroyGraph(Graph &G)
{
	EdgeNode *p,*u;        //边链表结点指针
	int vID;
	for(vID=1; vID<=G.VerNum; vID++)  //循环删除每个顶点的边链表
	{
		p=G.VerList[vID-1].firstEdge;
		G.VerList[vID-1].firstEdge=NULL;
		while(p)           //循环删除当前顶点所有的关联边
		{
			u=p->next;    //u指向下一个边结点
			delete(p);     //删除当前边结点
			p=u;
		}		
	}
	p=NULL;
	u=NULL;
	G.VerNum=-1;  //标识图已经销毁
}

8.4 运行截图

图2 运行截图
图3 运行截图
图4 遍历图dn10.grp
图5 求图dn10.grp的边数
图6 深度优先遍历图dn10.grp
图7 广度优先遍历图dn10.grp
图8 遍历森林ung114.grp
图9 求森林ung114.grp的边数
图10 深度优先遍历森林ung114.grp
图11 广度优先遍历森林ung114.grp
图12 遍历图ung8.grp
图13 求图ung8.grp的边数
图14 深度优先遍历图ung8.grp
图15 广度优先遍历图ung8.grp

部分测试数据与数据文件对照图:

数据文件dn10.grp:

//文件可以加注释行,注释以//开始,且必须顶头开始,不能有空格

//文件不能有空行

//Graph为图标志,否则判定格式不对

//标志行后,第一行为图的类型。UDG--无向图;UDN--无向网;DG--有向图;DN--有向网

//标志行后,第二行为顶点元素

//顶点行以下图的边或弧。用顶点表示,第一列以顶点编号排列;第二列为邻接点;在网中增加一列表示权值。

 

//此图为一个10个顶点、15条边的有向网。

 

 

 

//标识为图数据

                     Graph

 

//标识有向网

DN

 

//顶点数据列表,对应的编号为1,2,3,4,...

a b c d e f g h i j

 

 

//以下为边数据,共15条边

a b 2

a d 20

b e 1

c a 3

d c 8

d f 6

d g 4

e c 7

e h 3

f c 1

g h 1

h f 2

h j 2

i g 2

j i 1

图16 数据dn10.grp对照图

数据文件ung114.grp:

//文件可以加注释行,注释以//开始,且必须顶头开始,不能有空格

//文件不能有空行

//Graph为图标志,否则判定格式不对

//标志行后,第一行为图的类型。UDG--无向图;UDN--无向网;DG--有向图;DN--有向网

//标志行后,第二行为顶点元素

//顶点行以下图的边或弧。用顶点表示,第一列以顶点编号排列;第二列为邻接点;在网中增加一列表示权值。

 

//此图为一个有11个顶点、9条边的非连通的无向图。

                     Graph

UDG

 

//下面为顶点列表,对应的编号为1,2,3,4,...

a b c d e f g h i j k

 

//以下为邻接点(边)信息

//第一连通分量

a b

a d

b a

b c

c b

c d

d a

d c

//第二连通分量

e f

f e

f g

g f

//第三连通分量

h i

h k

i h

i j

j i

k h

图17 数据ung114.grp对照图

数据文件udg8.grp:

//文件可以加注释行,注释以//开始,且必须顶头开始,不能有空格

//文件不能有空行

//Graph为图标志,否则判定格式不对

//标志行后,第一行为图的类型。UDG--无向图;UDN--无向网;DG--有向图;DN--有向网

//标志行后,第二行为顶点元素

//顶点行以下图的边或弧。用顶点表示,第一列以顶点编号排列;第二列为邻接点;在网中增加一列表示权值。

 

//此图为一个有8个顶点、9条边的无向图。

                     Graph

UDG

 

//下面为顶点列表,对应的编号为1,2,3,4,...

a b c d e f g h

 

//以下为邻接点(边)信息

a b

a c

b a

b d

b e

c a

c g

c h

d b

d f

e b

e f

f d

f e

g c

g h

h c

h g

图18 数据udg8.grp对照图

 

8.5 附源代码

严正声明

此部分代码完全非本人所写,而是某个不具名大佬的手笔。本人秉着方便学习、互相交流的精神将代码贴在此处,原作者如有异议,请联系本人,即刻删除。

头文件 pch.h:

#ifndef PCH_H
#define PCH_H

// TODO: 添加要在此处预编译的标头
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <list>
#include <vector>
#include <stack>
#include <queue>

#endif //PCH_H

源文件 pch.cpp:

#include "pch.h"

#ifndef PCH_CPP
#define PCH_CPP



#endi

源文件 vNode.h:

#ifndef VNODE_H
#define VNODE_H

class vNode
{
public:
    vNode(int r_id, char r_data);
    int id();
    char data();
    bool flag1();
    void T_flag1();
    void F_flag1();
    bool flag2();
    void T_flag2();
    void F_flag2();
    bool flag3();
    void T_flag3();
    void F_flag3();
    void clear_flag();
    ~vNode();
private:
    int V_id;
    char V_data;
    bool V_flag1;
    bool V_flag2;
    bool V_flag3;
};

#endif

源文件 vNode.cpp:

#include "pch.h"

#ifndef VNODE_CPP
#define VNODE_CPP

#include "vNode.h"

vNode::vNode(int r_id, char r_data)
{
    this->V_id = r_id;
    this->V_data = r_data;
    this->V_flag1 = false;
    this->V_flag2 = false;
    this->V_flag3 = false;
}

int vNode::id()
{
    return this->V_id;
}

char vNode::data()
{
    return this->V_data;
}

bool vNode::flag1()
{
    return this->V_flag1;
}

void vNode::T_flag1()
{
    this->V_flag1 = true;
}

void vNode::F_flag1()
{
    this->V_flag1 = false;
}

bool vNode::flag2()
{
    return this->V_flag2;
}

void vNode::T_flag2()
{
    this->V_flag2 = true;
}

void vNode::F_flag2()
{
    this->V_flag2 = false;
}

bool vNode::flag3()
{
    return this->V_flag3;
}

void vNode::T_flag3()
{
    this->V_flag3 = true;
}

void vNode::F_flag3()
{
    this->V_flag3 = false;
}

void vNode::clear_flag()
{
    this->V_flag1 = false;
    this->V_flag2 = false;
    this->V_flag3 = false;
}


vNode::~vNode()
{
}

#endif

头文件 eNode.h:

#ifndef ENODE_H
#define ENODE_H

#include "vNode.cpp"

//#define INF 65535

class eNode
{
public:
    eNode(int r_id, vNode *v_begin, vNode *v_end, int r_len);
    int id();
    vNode *begin();
    vNode *end();
    int len();
    bool flag1();
    void T_flag1();
    void F_flag1();
    bool flag2();
    void T_flag2();
    void F_flag2();
    bool flag3();
    void T_flag3();
    void F_flag3();
    void clear_flag();
    ~eNode();
private:
    int E_id;
    vNode *E_begin;
    vNode *E_end;
    int E_len;
    bool E_flag1;
    bool E_flag2;
    bool E_flag3;
};

#endif

源文件 eNode.cpp:

#include "pch.h"

#ifndef ENODE_CPP
#define ENODE_CPP

#include "eNode.h"

eNode::eNode(int r_id, vNode *v_begin, vNode *v_end, int r_len)
{
    this->E_id = r_id;
    this->E_begin = v_begin;
    this->E_end = v_end;
    this->E_len = r_len;
    this->E_flag1 = false;
    this->E_flag2 = false;
    this->E_flag3 = false;
}

int eNode::id()
{
    return this->E_id;
}

vNode * eNode::begin()
{
    return this->E_begin;
}

vNode * eNode::end()
{
    return this->E_end;
}

int eNode::len()
{
    return this->E_len;
}

bool eNode::flag1()
{
    return this->E_flag1;
}

void eNode::T_flag1()
{
    this->E_flag1 = true;
}

void eNode::F_flag1()
{
    this->E_flag1 = false;
}

bool eNode::flag2()
{
    return this->E_flag2;
}

void eNode::T_flag2()
{
    this->E_flag2 = true;
}

void eNode::F_flag2()
{
    this->E_flag2 = false;
}

bool eNode::flag3()
{
    return this->E_flag3;
}

void eNode::T_flag3()
{
    this->E_flag3 = true;
}

void eNode::F_flag3()
{
    this->E_flag3 = false;
}

void eNode::clear_flag()
{
    this->E_flag1 = false;
    this->E_flag2 = false;
    this->E_flag3 = false;
}


eNode::~eNode()
{
}

#endif

头文件 adjListNode.h:

#ifndef ADJLISTNODE_H
#define ADJLISTNODE_H

#include "vNode.cpp"
#include "eNode.cpp"

class adjListNode
{
public:
    adjListNode(vNode *r_v);
    vNode *v();
    std::list<eNode *> &eList();
    void add_adj_e(eNode *r_e);
    eNode *get_first_adj_e();
    eNode *get_next_adj_e(eNode *e);
    void clear();
    ~adjListNode();
private:
    vNode *N_v;
    std::list<eNode *> N_eList;
};

#endif

源文件 adjListNode.cpp:

#include "pch.h"

#ifndef ADJLISTNODE_CPP
#define ADJLISTNODE_CPP

#include "adjListNode.h"

adjListNode::adjListNode(vNode *r_v)
{
    this->N_v = r_v;
}

vNode * adjListNode::v()
{
    return this->N_v;
}

std::list<eNode*>& adjListNode::eList()
{
    // TODO: 在此处插入 return 语句
    return this->N_eList;
}

void adjListNode::add_adj_e(eNode * r_e)
{
    this->N_eList.push_back(r_e);
}

eNode * adjListNode::get_first_adj_e()
{
    if (!this->N_eList.empty())
    {
        return this->N_eList.front();
    }
    return NULL;
}

eNode * adjListNode::get_next_adj_e(eNode * e)
{
    std::list <eNode *>::iterator i = this->N_eList.begin();
    while (i != this->N_eList.end())
    {
        if (*i == e)
        {
            ++i;
            break;
        }
        i++;
    }
    if (i != this->N_eList.end())
    {
        return *i;
    }
    return NULL;
}

void adjListNode::clear()
{
    this->N_eList.clear();
}


adjListNode::~adjListNode()
{
}

#endif

头文件 graph.h:

#include "pch.h"

#ifndef GRAPH_H
#define GRAPH_H

#include "vNode.cpp"
#include "eNode.cpp"
#include "adjListNode.cpp"

#ifndef MAX_V_NUM
#define MAX_V_NUM 40

#endif

class graph
{
public:
    graph();
    graph(const char *fileName);
    int init_list(void);
    int dfsTraversal_l();
    int dfsTraversal_l(vNode *V);
    int dfs_l(vNode *V);
    int bfsTraversal_l();
    int bfsTraversal_l(vNode *V);
    int bfs_l(vNode *V);
    int dfsTraversal_t_l();
    int dfsTraversal_t_l(vNode *V);
    int dfs_t_l(vNode *V, std::list<vNode *>&Lv, std::list<eNode *>&Le);
    int bfsTraversal_t_l();
    int bfsTraversal_t_l(vNode *V);
    int bfs_t_l(vNode *V, std::list<vNode *>&Lv, std::list<eNode *>&Le);
    int get_Enum_l();
    int Prim_l(vNode *V);
    int Kruskal_l(void);
    int Dijkstra_l(vNode *V);
    int Floyd_l(void);
    int AOV_l(void);
    int AOE_l(void);
    int dfsTraversal_m();
    int dfs_m(vNode *V);
    bool empty(void);
    bool error(void);
    vNode *getNode_for_data(const char n_data);
    vNode *getNode_for_ID(const int id);
    int clear_vFlag();
    int clear_eFlag();
    int clear_eFlag_l();
    int coverGraph(const char *fileName);
    int delete_G(void);
    ~graph();
private:
    bool G_empty;
    bool G_error;
    bool G_U;
    bool G_N;
    int G_type;
    int G_Vnum;
    int G_Enum;
    vNode *G_vList[MAX_V_NUM];
    std::list<eNode *> G_eList;
    eNode *G_adjMat[MAX_V_NUM][MAX_V_NUM];
    std::list<adjListNode *> G_adjList;
    std::list<adjListNode *> G_i_adjList;
};

#endif

源文件 graph.cpp:

#include "pch.h"

#ifndef GRAPH_CPP
#define GRAPH_CPP

#include "graph.h"

graph::graph()
{
    this->G_empty = true;
}

graph::graph(const char *fileName)
{
    int i;
    int j;
    i = 0;
    while (i < MAX_V_NUM)
    {
        this->G_vList[i] = NULL;
        j = 0;
        while (j < MAX_V_NUM)
        {
            this->G_adjMat[i][j] = NULL;
            j++;
        }
        i++;
    }
    
    this->coverGraph(fileName);
}

int graph::init_list(void)
{
    int i;
    adjListNode *pa = NULL;
    std::list<eNode *>::iterator i_e;
    std::list<adjListNode *>::iterator i_a;
    std::list<adjListNode *>::iterator i_i_a;
    i = 0;
    while (i < this->G_Vnum)
    {
        pa = new adjListNode(this->G_vList[i]);
        if (pa != NULL)
        {
            this->G_adjList.push_back(pa);
        }
        pa = new adjListNode(this->G_vList[i]);
        if (pa != NULL)
        {
            this->G_i_adjList.push_back(pa);
        }
        else
        {
            return -1;
        }
        i++;
    }
    i_e = this->G_eList.begin();
    while (i_e != this->G_eList.end())
    {
        i_a = this->G_adjList.begin();
        while (i_a != this->G_adjList.end())
        {
            if ((*i_a)->v()->data() == (*i_e)->begin()->data())
            {
                (*i_a)->add_adj_e(*i_e);
                break;
            }
            i_a++;
        }
        i_i_a = this->G_i_adjList.begin();
        while (i_i_a != this->G_i_adjList.end())
        {
            if ((*i_i_a)->v()->data() == (*i_e)->end()->data())
            {
                (*i_i_a)->add_adj_e(*i_e);
                break;
            }
            i_i_a++;
        }
        if (i_a == this->G_adjList.end() || i_i_a == this->G_i_adjList.end())
        {
            return -1;
        }
        i_e++;
    }
    return 0;
}

int graph::dfsTraversal_l()
{
    int i;
    std::cout << "深度优先遍历序列为:" << std::endl;
    this->clear_vFlag();
    i = 0;
    while (i < this->G_Vnum)
    {
        if (!this->G_vList[i]->flag1())
        {
            dfs_l(this->G_vList[i]);
        }
        i++;
    }
    std::cout << std::endl;
    return 0;
}

int graph::dfsTraversal_l(vNode * V)
{
    int i;
    if (V == NULL)
    {
        std::cout << "结点不存在!" << std::endl;
        return -1;
    }
    std::cout << "深度优先遍历序列为:" << std::endl;
    this->clear_vFlag();
    dfs_l(V);
    i = 0;
    while (i < this->G_Vnum)
    {
        if (!this->G_vList[i]->flag1())
        {
            dfs_l(this->G_vList[i]);
        }
        i++;
    }
    std::cout << std::endl;
    return 0;
}

int graph::dfs_l(vNode *V)
{
    std::list<adjListNode *>::iterator i_a;
    eNode *p_e;
    if (V == NULL)
    {
        return -1;
    }
    if (V->flag1())
    {
        return 0;
    }
    std::cout << V->data() << ' ';
    V->T_flag1();
    i_a = this->G_adjList.begin();
    while (i_a != this->G_adjList.end())
    {
        if ((*i_a)->v() == V)
        {
            break;
        }
        i_a++;
    }
    if (i_a == this->G_adjList.end())
    {
        return -1;
    }
    p_e = (*i_a)->get_first_adj_e();
    while (p_e != NULL)
    {
        //std::cout << p_e->begin()->data() << ' ' << p_e->end()->data() << std::endl;
        dfs_l(p_e->end());
        p_e = (*i_a)->get_next_adj_e(p_e);
    }
    return 0;
}

int graph::bfsTraversal_l()
{
    int i;
    std::cout << "广度优先遍历序列为:" << std::endl;
    this->clear_vFlag();
    i = 0;
    while (i < this->G_Vnum)
    {
        if (!this->G_vList[i]->flag1())
        {
            bfs_l(this->G_vList[i]);
        }
        i++;
    }
    std::cout << std::endl;
    return 0;
}

int graph::bfsTraversal_l(vNode * V)
{
    int i;
    if (V == NULL)
    {
        std::cout << "结点不存在!" << std::endl;
        return -1;
    }
    std::cout << "广度优先遍历序列为:" << std::endl;
    this->clear_vFlag();
    bfs_l(V);
    i = 0;
    while (i < this->G_Vnum)
    {
        if (!this->G_vList[i]->flag1())
        {
            bfs_l(this->G_vList[i]);
        }
        i++;
    }
    std::cout << std::endl;
    return 0;
}

int graph::bfs_l(vNode * V)
{
    vNode *p;
    std::queue<vNode *> Q;
    std::list<adjListNode *>::iterator i_a;
    std::list<eNode *>::iterator i_e;
    if (V == NULL)
    {
        return -1;
    }
    Q.push(V);
    while (!Q.empty())
    {
        p = Q.front();
        Q.pop();
        if (p->flag1())
        {
            continue;
        }
        std::cout << p->data() << ' ';
        p->T_flag1();
        i_a = this->G_adjList.begin();
        while (i_a != this->G_adjList.end())
        {
            if ((*i_a)->v()->data() == p->data())
            {
                break;
            }
            i_a++;
        }
        if (i_a == this->G_adjList.end())
        {
            return -1;
        }
        i_e = (*i_a)->eList().begin();
        while (i_e != (*i_a)->eList().end())
        {
            if (!(*i_e)->end()->flag1())
            {
                Q.push((*i_e)->end());
            }
            i_e++;
        }
    }
    return 0;
}

int graph::dfsTraversal_t_l()
{
    int i;
    std::list<vNode*> Lv;
    std::list<eNode*> Le;
    std::list<vNode*>::iterator iv;
    std::list<eNode*>::iterator ie;
    std::cout << "深度优先遍历序列为:" << std::endl;
    this->clear_vFlag();
    i = 0;
    while (i < this->G_Vnum)
    {
        if (!this->G_vList[i]->flag1())
        {
            dfs_t_l(this->G_vList[i], Lv, Le);
        }
        i++;
    }
    std::cout << std::endl;
    std::cout << "深度优先遍历生成树(森林)如下:" << std::endl;
    std::cout << "点集:" << std::endl;
    iv = Lv.begin();
    while (iv != Lv.end())
    {
        std::cout << (*iv)->data() << ' ';
        iv++;
    }
    std::cout << std::endl;
    std::cout << "边集:" << std::endl;
    ie = Le.begin();
    while (ie != Le.end())
    {
        std::cout << (*ie)->begin()->data();
        if (G_U)
        {
            std::cout << '-';
        }
        else
        {
            std::cout << "->";
        }
        std::cout << (*ie)->end()->data() << std::endl;
        ie++;
    }
    std::cout << std::endl;
    return 0;
}

int graph::dfsTraversal_t_l(vNode * V)
{
    int i;
    std::list<vNode*> Lv;
    std::list<eNode*> Le;
    std::list<vNode*>::iterator iv;
    std::list<eNode*>::iterator ie;
    if (V == NULL)
    {
        std::cout << "结点不存在!" << std::endl;
        return -1;
    }
    std::cout << "深度优先遍历序列为:" << std::endl;
    this->clear_vFlag();
    dfs_t_l(V, Lv, Le);
    i = 0;
    while (i < this->G_Vnum)
    {
        if (!this->G_vList[i]->flag1())
        {
            dfs_t_l(this->G_vList[i], Lv, Le);
        }
        i++;
    }
    std::cout << std::endl;
    std::cout << "深度优先遍历生成树(森林)如下:" << std::endl;
    std::cout << "点集:" << std::endl;
    iv = Lv.begin();
    while (iv != Lv.end())
    {
        std::cout << (*iv)->data() << ' ';
        iv++;
    }
    std::cout << std::endl;
    std::cout << "边集:" << std::endl;
    ie = Le.begin();
    while (ie != Le.end())
    {
        std::cout << (*ie)->begin()->data();
        if (G_U)
        {
            std::cout << '-';
        }
        else
        {
            std::cout << "->";
        }
        std::cout << (*ie)->end()->data() << std::endl;
        ie++;
    }
    std::cout << std::endl;
    return 0;
}

int graph::dfs_t_l(vNode * V, std::list<vNode*>& Lv, std::list<eNode*>& Le)
{
    std::list<adjListNode *>::iterator i_a;
    eNode *p_e;
    if (V == NULL)
    {
        return -1;
    }
    if (V->flag1())
    {
        Le.pop_back();
        return 0;
    }
    std::cout << V->data() << ' ';
    V->T_flag1();
    Lv.push_back(V);
    i_a = this->G_adjList.begin();
    while (i_a != this->G_adjList.end())
    {
        if ((*i_a)->v() == V)
        {
            break;
        }
        i_a++;
    }
    if (i_a == this->G_adjList.end())
    {
        return -1;
    }
    p_e = (*i_a)->get_first_adj_e();
    while (p_e != NULL)
    {
        //std::cout << p_e->begin()->data() << ' ' << p_e->end()->data() << std::endl;
        Le.push_back(p_e);
        dfs_t_l(p_e->end(), Lv, Le);
        p_e = (*i_a)->get_next_adj_e(p_e);
    }
    return 0;
}

int graph::bfsTraversal_t_l()
{
    int i;
    std::list<vNode*> Lv;
    std::list<eNode*> Le;
    std::list<vNode*>::iterator iv;
    std::list<eNode*>::iterator ie;
    std::cout << "广度优先遍历序列为:" << std::endl;
    this->clear_vFlag();
    i = 0;
    while (i < this->G_Vnum)
    {
        if (!this->G_vList[i]->flag1())
        {
            bfs_t_l(this->G_vList[i], Lv, Le);
        }
        i++;
    }
    std::cout << std::endl;
    std::cout << "广度优先遍历生成树(森林)如下:" << std::endl;
    std::cout << "点集:" << std::endl;
    iv = Lv.begin();
    while (iv != Lv.end())
    {
        std::cout << (*iv)->data() << ' ';
        iv++;
    }
    std::cout << std::endl;
    std::cout << "边集:" << std::endl;
    ie = Le.begin();
    while (ie != Le.end())
    {
        std::cout << (*ie)->begin()->data();
        if (G_U)
        {
            std::cout << '-';
        }
        else
        {
            std::cout << "->";
        }
        std::cout << (*ie)->end()->data() << std::endl;
        ie++;
    }
    std::cout << std::endl;
    return 0;
}

int graph::bfsTraversal_t_l(vNode * V)
{
    int i;
    std::list<vNode*> Lv;
    std::list<eNode*> Le;
    std::list<vNode*>::iterator iv;
    std::list<eNode*>::iterator ie;
    if (V == NULL)
    {
        std::cout << "结点不存在!" << std::endl;
        return -1;
    }
    std::cout << "广度优先遍历序列为:" << std::endl;
    this->clear_vFlag();
    bfs_t_l(V, Lv, Le);
    i = 0;
    while (i < this->G_Vnum)
    {
        if (!this->G_vList[i]->flag1())
        {
            bfs_t_l(this->G_vList[i], Lv, Le);
        }
        i++;
    }
    std::cout << std::endl;
    std::cout << "广度优先遍历生成树(森林)如下:" << std::endl;
    std::cout << "点集:" << std::endl;
    iv = Lv.begin();
    while (iv != Lv.end())
    {
        std::cout << (*iv)->data() << ' ';
        iv++;
    }
    std::cout << std::endl;
    std::cout << "边集:" << std::endl;
    ie = Le.begin();
    while (ie != Le.end())
    {
        std::cout << (*ie)->begin()->data();
        if (G_U)
        {
            std::cout << '-';
        }
        else
        {
            std::cout << "->";
        }
        std::cout << (*ie)->end()->data() << std::endl;
        ie++;
    }
    std::cout << std::endl;
    return 0;
}

int graph::bfs_t_l(vNode * V, std::list<vNode*>& Lv, std::list<eNode*>& Le)
{
    vNode *p;
    std::queue<vNode *> Q;
    std::list<adjListNode *>::iterator i_a;
    std::list<eNode *>::iterator i_e;
    if (V == NULL || V->flag1())
    {
        return -1;
    }
    Q.push(V);
    V->T_flag1();
    while (!Q.empty())
    {
        p = Q.front();
        Q.pop();
        std::cout << p->data() << ' ';
        Lv.push_back(p);
        i_a = this->G_adjList.begin();
        while (i_a != this->G_adjList.end())
        {
            if ((*i_a)->v()->data() == p->data())
            {
                break;
            }
            i_a++;
        }
        if (i_a == this->G_adjList.end())
        {
            return -1;
        }
        i_e = (*i_a)->eList().begin();
        while (i_e != (*i_a)->eList().end())
        {
            if (!(*i_e)->end()->flag1())
            {
                Q.push((*i_e)->end());
                (*i_e)->end()->T_flag1();
                Le.push_back(*i_e);
            }
            i_e++;
        }
    }
    return 0;
}

int graph::get_Enum_l()
{
    int e_num = 0;
    std::list<adjListNode *>::iterator i_a = this->G_adjList.begin();
    while (i_a != this->G_adjList.end())
    {
        e_num += (*i_a)->eList().size();
        i_a++;
    }
    if (G_U)
    {
        e_num /= 2;
    }
    return e_num;
}

int graph::Prim_l(vNode * V)
{
    int i = 0;
    int num = 1;
    vNode *pv = NULL;
    eNode *pe = NULL;
    std::list<vNode *> V_l;
    std::list<vNode *>::iterator iv;
    std::list<eNode *> E_l;
    std::list<eNode *> E_l2;
    std::list<eNode *>::iterator ie;
    std::list<adjListNode *>::iterator ia;
    if (V == NULL)
    {
        return -1;
    }
    this->clear_vFlag();
    V_l.push_back(V);
    while (E_l.size() < this->G_Vnum - 1)
    {
        pv = V_l.back();
        pv->T_flag1();
        ie = E_l2.begin();
        while (ie != E_l2.end())
        {
            if ((*ie)->end()->flag1())
            {
                ie = E_l2.erase(ie);
            }
            else
            {
                ie++;
            }
        }
        ia = this->G_adjList.begin();
        while (ia != this->G_adjList.end())
        {
            if ((*ia)->v()->data() == pv->data())
            {
                break;
            }
            ia++;
        }
        if (ia == this->G_adjList.end())
        {
            return -1;
        }
        ie = (*ia)->eList().begin();
        while (ie != (*ia)->eList().end())
        {
            if (!(*ie)->end()->flag1())
            {
                E_l2.push_back(*ie);
            }
            ie++;
        }
        if (!E_l2.empty())
        {
            ie = E_l2.begin();
            pe = (*ie);
            while (ie != E_l2.end())
            {
                if ((*ie)->len() < pe->len())
                {
                    pe = (*ie);
                }
                ie++;
            }
        }
        else
        {
            break;
        }
        E_l.push_back(pe);
        V_l.push_back(pe->end());
    }
    std::cout << "Prim算法:" << std::endl;
    std::cout << "起点:" << V->data() << std::endl;
    std::cout << "最小生成树如下:" << std::endl;
    std::cout << "点集:" << std::endl;
    iv = V_l.begin();
    while (iv != V_l.end())
    {
        std::cout << (*iv)->data() << ' ';
        iv++;
    }
    std::cout << std::endl;
    std::cout << "边集:" << std::endl;
    if (E_l.empty())
    {
        std::cout << "null!" << std::endl;
    }
    else
    {
        ie = E_l.begin();
        while (ie != E_l.end())
        {
            if (!this->G_U)
            {
                std::cout << (*ie)->begin()->data() << "->" << (*ie)->end()->data() << ' ';
            }
            else
            {
                std::cout << (*ie)->begin()->data() << '-' << (*ie)->end()->data() << ' ';
            }
            if (this->G_N)
            {
                std::cout << "len:" << (*ie)->len();
            }
            std::cout << std::endl;
            ie++;
        }
    }
    return 0;
}

int graph::Kruskal_l(void)
{
    int i;
    int low_f;
    int high_f;
    int V_f[MAX_V_NUM];
    std::list<eNode *> E_l;
    std::list<eNode *> E_l2;
    std::list<eNode *>::iterator ie;
    std::list<eNode *>::iterator ie2;
    std::list<adjListNode *>::iterator ia = this->G_adjList.begin();
    i = 0;
    while (i < this->G_Vnum)
    {
        V_f[this->G_vList[i]->id()] = this->G_vList[i]->id();
        i++;
    }
    while (ia != this->G_adjList.end())
    {
        ie = (*ia)->eList().begin();
        while (ie != (*ia)->eList().end())
        {
            ie2 = E_l2.begin();
            while (ie2 != E_l2.end() && (*ie)->len() > (*ie2)->len())
            {
                ie2++;
            }
            E_l2.insert(ie2, *ie);
            ie++;
        }
        ia++;
    }
    ie2 = E_l2.begin();
    while (ie2 != E_l2.end() && E_l.size() < this->G_Vnum - 1)
    {
        if (V_f[(*ie2)->begin()->id()] != V_f[(*ie2)->end()->id()])
        {
            E_l.push_back(*ie2);
            if ((*ie2)->begin()->id() < (*ie2)->end()->id())
            {
                low_f = V_f[(*ie2)->begin()->id()];
                high_f = V_f[(*ie2)->end()->id()];
            }
            else
            {
                low_f = V_f[(*ie2)->end()->id()];
                high_f = V_f[(*ie2)->begin()->id()];
            }
            i = 0;
            while (i < this->G_Vnum)
            {
                if (V_f[i] == high_f)
                {
                    V_f[i] = low_f;
                }
                //std::cout << V_f[i] << ' ';
                i++;
            }
            //std::cout << std::endl;
            //std::cout << "low:" << low_f << std::endl;
            //std::cout << "high:" << high_f << std::endl;
        }
        ie2++;
    }
    std::cout << "Kruskal算法:" << std::endl;
    std::cout << "最小生成树如下:" << std::endl;
    std::cout << "点集:" << std::endl;
    i = 0;
    while (i < this->G_Vnum)
    {
        std::cout << this->G_vList[i]->data() << ' ';
        //std::cout << "flag:" << V_f[i] << ' ';
        i++;
    }
    std::cout << std::endl;
    std::cout << "边集:" << std::endl;
    if (E_l.empty())
    {
        std::cout << "null!" << std::endl;
    }
    else
    {
        ie = E_l.begin();
        while (ie != E_l.end())
        {
            if (!this->G_U)
            {
                std::cout << (*ie)->begin()->data() << "->" << (*ie)->end()->data() << ' ';
            }
            else
            {
                std::cout << (*ie)->begin()->data() << '-' << (*ie)->end()->data() << ' ';
            }
            if (this->G_N)
            {
                std::cout << "len:" << (*ie)->len();
            }
            std::cout << std::endl;
            ie++;
        }
    }
    return 0;
}

int graph::Dijkstra_l(vNode * V)
{
    int i;
    int j;
    int V_pathLen[MAX_V_NUM];
    vNode *pv;
    eNode *pe;
    vNode *V_prior[MAX_V_NUM];
    std::list<eNode *>::iterator ie;
    std::list<adjListNode *>::iterator ia;
    std::stack<char> S_ch;

    if (V == NULL)
    {
        return -1;
    }

    this->clear_vFlag();

    i = 0;
    while (i < MAX_V_NUM)
    {
        V_pathLen[i] = -1;
        V_prior[i] = NULL;
        i++;
    }

    V_pathLen[V->id()] = 0;
    V->T_flag1();
    pv = V;
    do
    {
        pe = NULL;
        ia = this->G_adjList.begin();
        while (ia != this->G_adjList.end())
        {
            if ((*ia)->v()->flag1())
            {
                ie = (*ia)->eList().begin();
                while (ie != (*ia)->eList().end())
                {
                    if (!(*ie)->end()->flag1())
                    {
                        if (pe == NULL || 
                            pe->len() + V_pathLen[pe->begin()->id()] > 
                            (*ie)->len() + V_pathLen[(*ie)->begin()->id()])
                        {
                            pe = *ie;
                        }
                    }
                    ie++;
                }
            }
            ia++;
        }
        if (pe != NULL)
        {
            pe->end()->T_flag1();
            V_pathLen[pe->end()->id()] = V_pathLen[pe->begin()->id()] + pe->len();
            V_prior[pe->end()->id()] = pe->begin();
        }
    } while (pe != NULL);
    std::cout << "Dijkstra算法:" << std::endl;
    std::cout << "起点:" << V->data() << std::endl;
    std::cout << "从起点至其他各结点的最短路径如下:" << std::endl;
    i = 0;
    while (i < this->G_Vnum)
    {
        std::cout << V->data() << "->" << this->G_vList[i]->data() << ':';
        if (V_prior[i] != NULL)
        {
            j = i;
            while (V_prior[j] != NULL)
            {
                S_ch.push(this->getNode_for_ID(j)->data());
                j = V_prior[j]->id();
            }
            std::cout << V->data();
            while (!S_ch.empty())
            {
                std::cout << "->" << S_ch.top();
                S_ch.pop();
            }
            std::cout << " 路径长度:" << V_pathLen[i];
        }
        else if (V_pathLen[i] == 0)
        {
            std::cout << this->G_vList[i]->data();
            std::cout << " 路径长度:" << V_pathLen[i];
        }
        else
        {
            std::cout << "路径不存在!";
        }
        std::cout << std::endl;
        i++;
    }
    return 0;
}

int graph::Floyd_l(void)
{
    int i;
    int j;
    int k;
    int path_len[MAX_V_NUM][MAX_V_NUM];
    vNode *path[MAX_V_NUM][MAX_V_NUM];
    std::list<eNode *>::iterator ie;
    std::list<adjListNode *>::iterator ia;
    std::stack<char> S_ch;

    i = 0;
    while (i < this->G_Vnum)
    {
        j = 0;
        while (j < this->G_Vnum)
        {
            path[i][j] = NULL;
            if (i == j)
            {
                path_len[i][j] = 0;
            }
            else
            {
                path_len[i][j] = -1;
            }
            j++;
        }
        i++;
    }

    ia = this->G_adjList.begin();
    while (ia != this->G_adjList.end())
    {
        ie = (*ia)->eList().begin();
        while (ie != (*ia)->eList().end())
        {
            path[(*ie)->begin()->id()][(*ie)->end()->id()] = (*ie)->begin();
            path_len[(*ie)->begin()->id()][(*ie)->end()->id()] = (*ie)->len();
            ie++;
        }
        ia++;
    }

    k = 0;
    while (k < this->G_Vnum)
    {
        i = 0;
        while (i < this->G_Vnum)
        {
            j = 0;
            while (j < this->G_Vnum)
            {
                if (path[i][k] != NULL && path[k][j] != NULL && i != j)
                {
                    if (path[i][j] == NULL ||
                        path_len[i][k] + path_len[k][j] < path_len[i][j])
                    {
                        path[i][j] = this->G_vList[k];
                        path_len[i][j] = path_len[i][k] + path_len[k][j];
                    }
                }
                j++;
            }
            i++;
        }
        k++;
    }

    std::cout << "Floyd算法:" << std::endl;
    std::cout << "各对结点之间的最短路径如下:" << std::endl;
    i = 0;
    while (i < this->G_Vnum)
    {
        j = 0;
        while (j < this->G_Vnum)
        {
            std::cout << this->G_vList[i]->data() << "->" << this->G_vList[j]->data() << ':';
            if (path[i][j] != NULL)
            {
                k = j;
                while (path[i][k] != NULL && k != i)
                {
                    S_ch.push(this->G_vList[k]->data());
                    k = path[i][k]->id();
                }
                if (k != i)
                {
                    std::cout << "路径不存在!";
                }
                else
                {
                    std::cout << this->G_vList[i]->data();
                    while (!S_ch.empty())
                    {
                        std::cout << "->" << S_ch.top();
                        S_ch.pop();
                    }
                    std::cout << " 路径长度:" << path_len[i][j];
                }
            }
            else
            {
                if (i != j)
                {
                    std::cout << "路径不存在!";
                }
                else
                {
                    std::cout << this->G_vList[i]->data();
                    std::cout << " 路径长度:" << path_len[i][j];
                }
            }
            std::cout << std::endl;
            j++;
        }
        i++;
    }


    return 0;
}

int graph::AOV_l(void)
{
    int i;
    int deg_i[MAX_V_NUM];
    std::list<char> L_ch;
    vNode *pv;
    std::queue<vNode *> Q;
    std::list<adjListNode *>::iterator ia;
    std::list<eNode *>::iterator ie;

    this->clear_vFlag();

    i = 0;
    while (i < this->G_Vnum)
    {
        deg_i[i] = 0;
        i++;
    }

    ia = this->G_adjList.begin();
    while (ia != this->G_adjList.end())
    {
        ie = (*ia)->eList().begin();
        while (ie != (*ia)->eList().end())
        {
            deg_i[(*ie)->end()->id()] += 1;
            ie++;
        }
        ia++;
    }

    i = 0;
    while (i < this->G_Vnum)
    {
        if (deg_i[i] == 0)
        {
            Q.push(getNode_for_ID(i));
        }
        i++;
    }

    while (!Q.empty())
    {
        pv = Q.front();
        Q.pop();

        pv->T_flag1();
        L_ch.push_back(pv->data());

        ia = this->G_adjList.begin();
        while (ia != this->G_adjList.end())
        {
            if ((*ia)->v() == pv)
            {
                ie = (*ia)->eList().begin();
                while (ie != (*ia)->eList().end())
                {
                    deg_i[(*ie)->end()->id()] -= 1;
                    if (deg_i[(*ie)->end()->id()] == 0 && !(*ie)->end()->flag1())
                    {
                        Q.push((*ie)->end());
                    }
                    ie++;
                }
            }
            ia++;
        }
    }

    if (L_ch.size() < this->G_Vnum)
    {
        std::cout << "该图无拓扑序列!" << std::endl;
    }
    else
    {
        std::cout << "该图的拓扑序列为:";
        while (!L_ch.empty())
        {
            std::cout << L_ch.front() << ' ';
            L_ch.pop_front();
        }
        std::cout << std::endl;
    }

    return 0;
}

int graph::AOE_l(void)
{
    int i;
    int j;
    int len = 0;
    int deg_i[MAX_V_NUM];
    int deg_o[MAX_V_NUM];
    int minLs[MAX_V_NUM];
    int minLe[MAX_V_NUM];
    int maxLs[MAX_V_NUM];
    int maxLe[MAX_V_NUM];
    vNode *prior[MAX_V_NUM];
    vNode *pv;
    eNode *pe;
    std::list<vNode *> L;
    std::list<vNode *> path;
    std::list<vNode *>::iterator iv;
    std::list<adjListNode *>::iterator ia;
    std::list<eNode *>::iterator ie;

    this->clear_vFlag();
    this->clear_eFlag_l();

    i = 0;
    while (i < this->G_Vnum)
    {
        prior[i] = NULL;
        deg_i[i] = 0;
        deg_o[i] = 0;
        minLs[i] = 0;
        minLe[i] = 0;
        maxLs[i] = 0;
        maxLe[i] = 0;
        i++;
    }

    ia = this->G_adjList.begin();
    while (ia != this->G_adjList.end())
    {
        ie = (*ia)->eList().begin();
        while (ie != (*ia)->eList().end())
        {
            deg_i[(*ie)->end()->id()] += 1;
            deg_o[(*ie)->begin()->id()] += 1;
            ie++;
        }
        ia++;
    }

    i = 0;
    while (i < this->G_Vnum)
    {
        if (deg_i[i] == 0)
        {
            minLs[i] = 0;
            L.push_back(getNode_for_ID(i));
            getNode_for_ID(i)->T_flag1();
        }
        i++;
    }

    while (!L.empty())
    {
        iv = L.begin();
        while (iv != L.end())
        {
            maxLe[(*iv)->id()] = len;
            iv++;
        }

        pe = NULL;
        iv = L.begin();
        while (iv != L.end())
        {
            ia = this->G_adjList.begin();
            while (ia != this->G_adjList.end())
            {
                if ((*ia)->v() == (*iv))
                {
                    ie = (*ia)->eList().begin();
                    while (ie != (*ia)->eList().end())
                    {
                        if (!(*ie)->flag1())
                        {
                            if (pe == NULL || 
                                pe->len() - (maxLe[pe->begin()->id()] - minLs[pe->begin()->id()]) >
                                (*ie)->len() - (maxLe[(*ie)->begin()->id()] - minLs[(*ie)->begin()->id()]))
                            {
                                pe = *ie;
                            }
                        }
                        ie++;
                    }
                    break;
                }
                ia++;
            }
            iv++;
        }

        if (pe != NULL)
        {
            //std::cout << pe->begin()->data() << "->" << pe->end()->data() << std::endl;

            len += pe->len() - (maxLe[pe->begin()->id()] - minLs[pe->begin()->id()]);
            deg_i[pe->end()->id()] -= 1;
            deg_o[pe->begin()->id()] -= 1;
            pe->T_flag1();


            if (deg_o[pe->begin()->id()] == 0)
            {
                iv = L.begin();
                while (iv != L.end())
                {
                    if ((*iv) == pe->begin())
                    {
                        break;
                    }
                    iv++;
                }
                (*iv)->T_flag2();
                maxLe[(*iv)->id()] = len;
                //std::cout << (*iv)->data() << ' ';
                L.erase(iv);
            }

            if (deg_i[pe->end()->id()] == 0)
            {
                if (!pe->end()->flag1())
                {
                    minLs[pe->end()->id()] = len;
                    prior[pe->end()->id()] = pe->begin();
                    if (deg_o[pe->end()->id()] != 0)
                    {
                        L.push_back(pe->end());
                    }
                    else
                    {
                        if (!pe->end()->flag2())
                        {
                            maxLe[pe->end()->id()] = len + pe->len();
                            pe->end()->T_flag2();
                        }
                    }
                    pe->end()->T_flag1();
                }
            }
        }
        else
        {
            break;
        }
    }

    i = 0;
    j = 0;
    while (i < this->G_Vnum)
    {
        //std::cout << maxLe[i] << std::endl;
        if (maxLe[i] > maxLe[j])
        {
            j = i;
        }
        i++;
    }

    i = 0;
    while (i < this->G_Vnum)
    {
        if (!this->G_vList[i]->flag2())
        {
            std::cout << "该图不存在关键路径!" << std::endl;
            return 0;
        }
        i++;
    }

    pv = getNode_for_ID(j);
    while (pv != NULL)
    {
        path.push_front(pv);
        pv = prior[pv->id()];
    }
    std::cout << "该图的关键路径为:" << std::endl;
    iv = path.begin();
    while (iv != path.end())
    {
        std::cout << (*iv)->data();
        ++iv;
        if (iv != path.end())
        {
            std::cout << "->";
        }
    }
    std::cout << std::endl;
    std::cout << "关键路径的长度为:" << maxLe[j] << std::endl;

    return 0;
}

bool graph::empty(void)
{
    return this->G_empty;
}

bool graph::error(void)
{
    return this->G_error;
}

vNode * graph::getNode_for_data(const char n_data)
{
    int i = 0;
    while (i < this->G_Vnum)
    {
        if (this->G_vList[i] != NULL && this->G_vList[i]->data() == n_data)
        {
            break;
        }
        i++;
    }
    if (i >= this->G_Vnum)
    {
        return NULL;
    }
    return this->G_vList[i];
}

vNode * graph::getNode_for_ID(const int id)
{
    if (id >= 0 && id < this->G_Vnum)
    {
        return this->G_vList[id];
    }
    return NULL;
}

int graph::clear_vFlag()
{
    int i = 0;
    while (i < this->G_Vnum)
    {
        this->G_vList[i]->clear_flag();
        i++;
    }
    return 0;
}

int graph::clear_eFlag()
{
    std::list<eNode *>::iterator ie = this->G_eList.begin();
    while (ie != this->G_eList.end())
    {
        (*ie)->clear_flag();
        ie++;
    }
    return 0;
}

int graph::clear_eFlag_l()
{
    std::list<adjListNode *>::iterator ia = this->G_adjList.begin();
    std::list<eNode *>::iterator ie;
    while (ia != this->G_adjList.end())
    {
        ie = (*ia)->eList().begin();
        while (ie != (*ia)->eList().end())
        {
            (*ie)->clear_flag();
            ie++;
        }
        ia++;
    }
    return 0;
}

int graph::coverGraph(const char * fileName)
{
    bool error = false;
    bool typeLine = false;
    bool nodeLine = false;
    bool eLine = false;
    int elen;
    int vID = 0;
    int eID = 0;
    char ch_a;
    char ch_b;
    char str[256];
    vNode *pv = NULL;
    eNode *pe = NULL;
    std::ifstream fra;
    int ia;
    int ib;
    this->delete_G();
    fra.open(fileName);
    if (!fra.good())
    {
        this->G_error = true;
        return -3;
    }
    while (fra.good())
    {
        fra >> str;
        //std::cout << eID << '-';
        //std::cout << str << std::endl;
        if (strlen(str) == 0)
        {
            continue;
        }
        if (strncmp(str, "//", 2) == 0)
        {
            fra.getline(str, 255);
            continue;
        }
        if (!typeLine && !nodeLine && !eLine)
        {
            if (strcmp(str, "Graph") == 0)
            {
                typeLine = true;
                continue;
            }
        }
        if (typeLine)
        {
            if (strcmp(str, "UDG") == 0)
            {
                this->G_U = true;
                this->G_N = false;
            }
            else
            {
                if (strcmp(str, "DG") == 0)
                {
                    this->G_U = false;
                    this->G_N = false;
                }
                else
                {
                    if (strcmp(str, "UDN") == 0)
                    {
                        this->G_U = true;
                        this->G_N = true;
                    }
                    else
                    {
                        if (strcmp(str, "DN") == 0)
                        {
                            this->G_U = false;
                            this->G_N = true;
                        }
                        else
                        {
                            error = true;
                            break;
                        }
                    }
                }
            }
            typeLine = false;
            nodeLine = true;
            continue;
        }
        if (nodeLine)
        {
            ch_a = str[0];
            this->G_vList[vID] = new vNode(vID, ch_a);
            if (G_vList[vID] == NULL)
            {
                error = true;
                break;
            }
            vID += 1;
            if (!fra.good())
            {
                error = true;
                break;
            }
            ch_a = fra.get();
            while (ch_a != '\n')
            {
                //std::cout << ch_a << ' ';
                if (!isspace(ch_a))
                {
                    this->G_vList[vID] = new vNode(vID, ch_a);
                    if (G_vList[vID] == NULL)
                    {
                        error = true;
                        break;
                    }
                    vID += 1;
                }
                if (!fra.good())
                {
                    error = true;
                    break;
                }
                ch_a = fra.get();
            }
            //std::cout << std::endl;
            if (error)
            {
                break;
            }
            this->G_Vnum = vID;
            nodeLine = false;
            eLine = true;
            continue;
        }
        if (eLine)
        {
            ch_a = str[0];
            if (!fra.good())
            {
                error = true;
                break;
            }
            fra >> ch_b;
            if (this->G_N)
            {
                if (!fra.good())
                {
                    error = true;
                    break;
                }
                fra >> elen;
            }
            else
            {
                elen = 1;
            }
            //std::cout << ch_a << ' ' << ch_b << ' ' << elen << std::endl;
            ia = 0;
            while (ia < this->G_Vnum)
            {
                if (this->G_vList[ia]->data() == ch_a)
                {
                    break;
                }
                ia++;
            }
            ib = 0;
            while (ib < this->G_Vnum)
            {
                if (this->G_vList[ib]->data() == ch_b)
                {
                    break;
                }
                ib++;
            }
            if (ia >= G_Vnum || ib >= G_Vnum)
            {
                error = true;
                break;
            }
            //std::cout << eID << std::endl;
            pe = new eNode(eID, this->G_vList[ia], this->G_vList[ib], elen);
            eID += 1;
            if (pe != NULL)
            {
                this->G_adjMat[ia][ib] = pe;
                this->G_eList.push_back(pe);
            }
            else
            {
                error = true;
                break;
            }
        }
        str[0] = '\0';
    }
    fra.close();

    if (error)
    {
        this->G_error = true;
        return -4;
    }

    this->G_Enum = eID;
    if (this->G_U)
    {
        this->G_Enum /= 2;
    }

    if (this->init_list() != 0)
    {
        this->G_error = true;
        return -5;
    }

    this->G_empty = false;

    return 0;
}

int graph::delete_G(void)
{
    int i;
    int j;

    i = 0;
    while (i < MAX_V_NUM)
    {
        if (this->G_vList[i] != NULL)
        {
            delete this->G_vList[i];
            this->G_vList[i] = NULL;
        }
        i++;
    }

    while (!this->G_eList.empty())
    {
        delete this->G_eList.front();
        this->G_eList.pop_front();
    }

    while (!this->G_adjList.empty())
    {
        delete this->G_adjList.front();
        this->G_adjList.pop_front();
    }

    while (!this->G_i_adjList.empty())
    {
        delete this->G_i_adjList.front();
        this->G_i_adjList.pop_front();
    }

    i = 0;
    while (i < MAX_V_NUM)
    {
        j = 0;
        while (j < MAX_V_NUM)
        {
            this->G_adjMat[i][j] = NULL;
            j++;
        }
        i++;
    }

    this->G_empty = true;

    return 0;
}

graph::~graph()
{
    this->delete_G();
}

#undef MAX_V_NUM

#endif

测试数据与数据文件对照图下载

猜你喜欢

转载自blog.csdn.net/u25th_engineer/article/details/85856940
今日推荐