目录
实验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所示的有向网,完整的数据文件如下:
//标识为图数据
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 运行截图
部分测试数据与数据文件对照图:
数据文件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
数据文件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
数据文件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
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