图(邻接矩阵实现)(C++实现)

一、实验要求

    设计图(网)的邻接矩阵,编写算法实现下列问题的求解。

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

实验测试数据基本要求:

第一组数据: udg8.grp

第二组数据: udg115.grp

第三组数据: dg6.grp

 

2.求给定图中的边(或弧)的数目。   实验测试数据基本要求:

第一组数据: udg8.grp

第二组数据: udg115.grp

 

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

实验测试数据基本要求:

第一组数据: udg8.grp

第二组数据: dg6.grp

第三组数据: udg114.grp

 

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

第一组数据: udg8.grp

第二组数据: dg6.grp

第三组数据: udg114.grp

 

5.实现Prim算法,求解下列给定图G的最小生成树。  实验测试数据基本要求:第一组数据: udn6.grp

第二组数据: udn8.grp

 

6.实现Kruskal算法,求解下列给定图G的最小生成树。  实验测试数据基本要求:

第一组数据: udn6.grp

第二组数据: udn8.grp

 

7.实现Dijkstra算法,求解下列给定图G指定顶点到其余顶点之间的最短路径。    实验测试数据基本要求

第一组数据: udn8.grp

第二组数据: dn8.grp

 

8.实现Floyd算法,求解下列给定图G各顶点之间的最短路径。   实验测试数据基本要求:

第一组数据: udn8.grp

第二组数据: dn8.grp

 

9.设计算法求解下列给定图G的拓扑序列。    实验测试数据基本要求:

第一组数据: dn8.grp

第二组数据: kPath101.grp

 

10.设计算法求解下列给定AOE网的关键路径。 实验测试数据基本要求:

第一组数据: dn8.grp

第二组数据: kPath101.grp

二、数据结构设计

//图的邻接矩阵结构:
#define MaxVerNum  100    		 //定义最大顶点个数
typedef char elementType; 		 //定义图中顶点的数据类型
typedef int cellType;     		 //定义邻接矩阵中元素的数据类型
typedef enum{UDG, UDN, DG, DN} GraphKind;          //枚举图的类型
typedef struct GraphAdjMatrix
{
	elementType Data[MaxVerNum+1];					 //顶点数组,存放顶点元素的值,Data[0]单元不用
	cellType AdjMatrix[MaxVerNum+1][MaxVerNum+1];  //邻接矩阵,数组下标为0单元不用,从AdjMatrix[1][1]单元开始
	int VerNum;       //顶点数
	int ArcNum;       //弧(边)数
	GraphKind gKind;  //图的类型:0-无向图;1-无向网;2-有向图;3-有向网
} Graph;  //图的类型名

三、算法设计

       由于图的深度优先遍历(DFS)、广度优先遍历(BFS)、Prim算法及思想、Kruskal算法及思想、Dijkstra算法及思想、Floyd算法及思想、拓扑序列算法及思想、AOE网的关键路径算法思想书中已给出,这里不再赘述。

  •      深度优先遍历生成树算法及思想:修改深度优先遍历树和深度优先遍历森林算法。DFSTree()按照DFS()深度遍历相应递归生成孩子-兄弟表示的二叉树。而DFSForest()则分别处理每棵树,进而转化成森林(二叉链表表示)。算法描述:
//深度优先遍历生成树
void DFSTree(Graph &G,int v,csTree&T)
{
    int j,w,first=1;    //first标记是否为根节点,初始化为1
    csNode *p,*q;
    q=T;
    visited[v]=1;
    w=firstAdj(G,v);
    while(w!=0)             	//还存在邻接点
    {
        if(!visited[w]&&G.AdjMatrix[v][w]>=1 && G.AdjMatrix[v][w]<INF)
        {
            p=new csNode;
            p->firstChild=NULL;
            p->nextSibling=NULL;
            p->data=G.Data[w];
            if(first)           //(生成第一个孩子)
            {
                T->firstChild=p;
                first=0;
            }
            else{               //(生成节点的兄弟节点)
                q->nextSibling=p;
            }
            q=p;
            DFSTree(G,w,q);		//递归处理每个节点
        }
        w=nextAdj(G,v,w);
    }
}
//深度优先遍历生成森林
csTree DFSForest(Graph &G,csTree &T,int v)
{	//v指定生成树或森林的根节点
    int i;
    csNode *p;
    csTree q;
    T=NULL;
    for(i=1;i<=G.VerNum;i++)    //初始化visited数组
    {
        visited[i]=0;
    }
    for(v;v>=1;v--)             //编号1到v
    {
        if(!visited[v] )
        {
            p=new csNode;
            p->firstChild=NULL;
            p->nextSibling=NULL;
            p->data=G.Data[v];
            if(!T)              //为根节点
            {
                T=p;
                q=T;
            }
            else{               //生成数根节点的兄弟节点,也就是其他树的根节点
                q->nextSibling=p;
            }
            q=p;
            DFSTree(G,v,p);
        }
    }
    for(v+=1;v<=G.VerNum;v++)   //编号v到G.vernum
    {
        if(!visited[v] )
        {
            p=new csNode;
            p->firstChild=NULL;
            p->nextSibling=NULL;
            p->data=G.Data[v];
            if(!T)             //为根节点
            {
                T=p;
                q=T;
            }
            else{             //生成数根节点的兄弟节点,也就是其他树的根节点
                q->nextSibling=p;
            }
            q=p;
            DFSTree(G,v,p);  //处理每棵树
        }
    }
    return T;
}
  •        广度优先遍历生成树算法及思想:修改广度优先遍历树和广度优先遍历森林算法。BFSTree()按照BFS()广度遍历相应分层生成孩子-兄弟表示的二叉树。而BFSForest()则分别处理每棵树,进而转化成森林(二叉链表表示)。

算法描述:

//广度优先遍历生成树
void BFSTree(Graph &G,csTree&T,int v)
{
    int i,w;
    bool first=true;            //标志变量,判断是否生成孩子节点
    csNode *t,*q,*p;
    queue<int> Q;
    if(!T)                      //生成树的根节点
    {
        T=new csNode;
        T->data=G.Data[v];
        visited[v]=true;
        T->firstChild=T->nextSibling=NULL;
    }
    p=T;
    Q.push(v);
    //对其他层节点操作
    while(!Q.empty())
    {
        v=Q.front(); //获取队头编号
        Q.pop();     //并出队
        w=firstAdj(G,v);
        first=true;  //循环i层时需要把first置为true,以便生成T->firstChild
        while(w!=0)
        {
            if(!visited[w]&& G.AdjMatrix[v][w]>=1 && G.AdjMatrix[v][w]<INF)
            {
                Q.push(w);             //第i层节点入队
                visited[w]=true;       //设置其访问标志
                q=new csNode;
                q->data=G.Data[w];
                q->firstChild=q->nextSibling=NULL;
                if(first)              //生成孩子节点
                {
                    p->firstChild=q;
                    first=false;
                }
                else{                   //生成兄弟节点
                    p->nextSibling=q;
                }
                p=q;
            }
            w=nextAdj(G,v,w);
        }
    }
}

广度优先生成森林与深度优先生成森林代码处理相同,故不再赘述。

四、代码实现

#ifndef _GRPADJMATRIX_H_
#define _GRPADJMATRIX_H_

#include <iostream>

using namespace std;
//************************************************************//
//*    图的邻接矩阵存储的头文件,文件名:grpAdjMatrix.h      *//
//*                                                          *//
//************************************************************//

#define INF 65535          //定义无穷大
#define MaxVerNum  100     //定义最大顶点个数
//typedef int elementType;  //定义图中顶点的数据类型
typedef char elementType;  //定义图中顶点的数据类型
typedef int cellType;      //定义邻接矩阵中元素的数据类型
                           //对无权图,1-相邻(有边),0-不相邻(无边)
                           //对有权图,为边的权值,特别是无穷大。
                           //枚举图的类型--无向图(UDG),无向网(UDN),有向图(DG),有向网(DN)
typedef enum{UDG, UDN, DG, DN} GraphKind;

bool visited[MaxVerNum+1];  //全局数组,标记顶点是否已经访问,visited[0]单元不用

//****************************************************//
//*  定义邻接矩阵表示的图结构。5个分量组成:         *//
//*      data[]数组保存图中顶点数据元素              *//
//*      AdjMatrix[][]邻接矩阵                       *//
//*      VerNum顶点个数                              *//
//*      ArcNum边(弧)条数                          *//
//*      gKind枚举图的类型                           *//
//*  考虑到名称的统一性,图类型名称定义为Graph       *//
//****************************************************//
typedef struct GraphAdjMatrix
{
	elementType Data[MaxVerNum+1];                 //顶点数组,存放顶点元素的值,Data[0]单元不用
	cellType AdjMatrix[MaxVerNum+1][MaxVerNum+1];  //邻接矩阵,数组下标为0单元不用,从AdjMatrix[1][1]单元开始
	int VerNum;       //顶点数
	int ArcNum;       //弧(边)数
	GraphKind gKind;  //图的类型:0-无向图;1-无向网;2-有向图;3-有向网
} Graph;  //图的类型名

//******************* 访问图中顶点的函数*********************//
//* 函数功能:打印图中顶点元素,并标记为已经访问            *//
//* 入口参数  Graph G,待访问的图;int verID 目标顶点编号   *//
//* 出口参数:无                                            *//
//* 返 回 值:空                                            *//
//* 函 数 名:visit(Graph &G, int verID)                    *//
//***********************************************************//
void visit(Graph &G, int verID)
{        //顶点编号从1开始,数组0单元不用
	cout<<G.Data[verID]<<" ";
	visited[verID]=true;
}
//*******************  图中查找目标顶点 *********************//
//* 函数功能:给定顶点元素,在图中查找此顶点元素            *//
//* 入口参数  Graph G,待访问的图;elementType v 目标顶点   *//
//* 出口参数:无                                            *//
//* 返 回 值:int。如果目标顶点存在,返回顶点编号,         *//
//*                顶点编号从1开始;否则返回-1              *//
//* 函 数 名:visit(Graph &G, int verID)                    *//
//***********************************************************//
int LocateVertex(Graph &G, elementType v)
{
	for(int i=1;i<=G.VerNum;i++)
	{
		if( G.Data[i]==v )
			return i;
	}
	return -1;
}
//求顶点v的第一个邻接点
int firstAdj(Graph &G,int v)
{
	int w;
	for(w=1;w<=G.VerNum;w++)
	{
		if((G.AdjMatrix[v][w]>=1)&&(G.AdjMatrix[v][w])<INF)
		   return w;    //返回第一个邻接点编号
	}
	 return 0;          //未找到邻接点,返回0
}
//求顶点v的位于邻接点w后的下一个邻接点
int nextAdj(Graph &G,int v,int w)
{
	int k;
	for(k=w+1;k<=G.VerNum;k++)
	{
		if((G.AdjMatrix[v][k]>=1) && (G.AdjMatrix[v][k])<INF)
		   return k;    //返回v的位于w之后的下一个邻接点k
	}
	return 0;           //不存在下一个邻接点,返回0
}

//******************** 打印图的相关信息 *********************//
//* 函数功能:打印图的相关信息                              *//
//* 入口参数:Graph G,待打印的图                           *//
//* 出口参数:无                                            *//
//* 返 回 值:空                                            *//
//* 函 数 名:GraphPrint(Graph &G)                          *//
//***********************************************************//
void printGraph(Graph &G)
{
	int i=0,j=0;
	//打印图的类型
	switch(G.gKind)
	{
	case UDG:
		cout<<"图类型:无向图"<<endl;
		break;
	case UDN:
		cout<<"图类型:无向网"<<endl;
		break;
	case DG:
  	    cout<<"图类型:有向图"<<endl;
		break;
	case DN:
		cout<<"图类型:有向网"<<endl;
		break;
	default:
		cout<<"图类型错误。"<<endl;
		break;
	}
	//打印图的顶点数
	cout<<"顶点数:"<<G.VerNum<<endl;
	//打印图的边数
	cout<<"边  数:"<<G.ArcNum<<endl;
	//打印顶点及其编号
	cout<<"编  号:";
	for(i=1;i<=G.VerNum;i++)
	{
		cout<<i<<"\t";
	}
	cout<<endl;
	cout<<"顶  点:";
	for(i=1;i<=G.VerNum;i++)
	{
		cout<<G.Data[i]<<"\t";
	}
	cout<<endl;

	//打印邻接矩阵
	cout<<"图的邻接矩阵:"<<endl;
	for(i=1;i<=G.VerNum;i++)
	{
		cout<<"\t";
		for(j=1;j<=G.VerNum;j++)
		{
			if((G.gKind==UDN || G.gKind==DN) && G.AdjMatrix[i][j]==INF)
				cout<<"INF"<<"\t";  //网,无穷大时,打印“INF”表示
			else
				cout<<G.AdjMatrix[i][j]<<"\t";
		}
		cout<<endl;
	}
}
#endif // _GRPADJMATRIX_H_
#ifndef _CREATEGRPADJMATRIX_H_
#define _CREATEGRPADJMATRIX_H_

#include "grpAdjMatrix.h"
#include <cstring>
#include <cstdio>
#include <cstdlib>

using namespace std;

void strLTrim(char* str);


//*************************从数据文件创建图**************************//
//* 函数功能:从文本文件创建邻接矩阵表示的图                        *//
//* 入口参数  char fileName[],文件名                               *//
//* 出口参数:                                                      *//
//* 返 回 值:bool,true创建成功;false创建失败                     *//
//* 函 数 名:CreateGrpFromFile(char fileName[])                  *//
//*******************************************************************//
bool CreateGrpFromFile(char fileName[], Graph &G)
{
	FILE* pFile;      //定义顺序表的文件指针
	char str[1000];   //存放读出一行文本的字符串
	char strTemp[10]; //判断是否注释行

	cellType  eWeight;     //边的信息,常为边的权值
	GraphKind GrpType;  //图类型枚举变量

	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中应该已经是文件标识,判断文件格式
	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"))
		GrpType=UDG;  //无向图
	else if(strstr(str,"UDN"))
		GrpType=UDN;  //无向网
	else if(strstr(str,"DG"))
		GrpType=DG;   //有向图
	else if(strstr(str,"DN"))
		GrpType=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=1;
	while(token!=NULL)
	{
		G.Data[nNum]=*token; // atoi(token);	//顶点数据转换为整数,若为字符则不需转换
        token = strtok( NULL, " ");
		nNum++;
	}
	nNum--;   //顶点数

    //图的邻接矩阵初始化
	int nRow=1;  //矩阵行下标,从1开始
	int nCol=1;  //矩阵列下标,从1开始
	if(GrpType==UDG || GrpType==DG)
	{
		for(nRow=1;nRow<=nNum;nRow++)
			for(nCol=1;nCol<=nNum;nCol++)
				G.AdjMatrix[nRow][nCol]=0;
	}
	else
	{
		for(nRow=1;nRow<=nNum;nRow++)
			for(nCol=1;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=1;nRow<=nNum;nRow++)
		{
			if(G.Data[nRow]==Nf)  //从顶点列表找到第一个顶点的编号
				break;
		}
           //从第二个顶点获取列号
		for(nCol=1;nCol<=nNum;nCol++)
		{
			if(G.Data[nCol]==Ns)  //从顶点列表找到第二个顶点的编号
				break;
		}

		//如果为网,读取权值
		if(GrpType==UDN || GrpType==DN)
		{
			token = strtok( NULL, " ");  //读取下一个子串,即边的附加信息,常为边的权重
			if(token==NULL)  //分割为空串,失败退出
			{
				printf("错误:读取图的边数据失败!\n");
				fclose(pFile); //关闭文件
				return false;
			}
			eWeight=atoi(token);  //取得边的附加信息
		}
		if(GrpType==UDN || GrpType==DN)  //如果为网,邻接矩阵中对应的边设置权值,否则置为1
			G.AdjMatrix[nRow][nCol]=eWeight;
		else
			G.AdjMatrix[nRow][nCol]=1;  //atoi(token);	//字符串转为整数

		edgeNum++;   //边数加1
	}

    G.VerNum=nNum;  //图的顶点数
	if(GrpType==UDG || GrpType==UDN)
		G.ArcNum=edgeNum / 2;  //无向图或网的边数等于统计的数字除2
	else
		G.ArcNum=edgeNum;

	G.gKind=GrpType;  //图的类型

	fclose(pFile); //关闭文件
	return true;
}

//删除字符串、字符数组左边空格
void strLTrim(char* str)
{
	int i,j;
	int n=0;
	n=strlen(str)+1;
	for(i=0;i<n;i++)
	{
		if(str[i]!=' ')  //找到左起第一个非空格位置
			break;
	}
	    //以第一个非空格字符为手字符移动字符串
	for(j=0;j<n;j++)
	{
		str[j]=str[i];
		i++;
	}
}
#endif // _CREATEGRPADJMATRIX_H_
#ifndef _TREE_H_
#define _TREE_H_

#include <iostream>
#include <queue>

using namespace std;

//树(森林)的孩子兄弟链表表示
typedef char elementType;

typedef struct csNode
{
	elementType data;
	struct csNode *firstChild, *nextSibling;
}csNode,*csTree;

//先序遍历森林
void perOrderTraverse(csNode *T)
{
    if(T)
    {
        cout<<T->data<<" ";           //访问根节点
        perOrderTraverse(T->firstChild);  //递归调用先序遍历左子树
        perOrderTraverse(T->nextSibling);  //递归调用先序遍历右子树
    }
}
//后序遍历森林
void postOrderTraverse(csNode *T)
{
    if(T)
    {
        postOrderTraverse(T->firstChild);  //递归调用先序遍历左子树
        postOrderTraverse(T->nextSibling);  //递归调用先序遍历右子树
        cout<<T->data<<" ";            //访问根节点
    }
}
//层次遍历森林
void levelOrderTraverse(csNode *T)
{
    queue<csNode *> q;
    csNode * u,*n,*p;
    if(T==NULL)
    {
        return;
    }
    n=T;
    while(n)
    {
        p=n;
        q.push(p);
        while(!q.empty())
        {
            p=q.front();
            cout<<p->data<<" ";
            u=p->firstChild;
            while(u)
            {
                p=u;
                q.push(p);
                u=u->nextSibling;
            }
            q.pop();
        }
        n=n->nextSibling;
    }
}
//销毁森林
void destroy(csNode *&T)
{
    if(T)
    {
        destroy(T->firstChild);
        destroy(T->nextSibling);
        delete T;
    }
}
#endif // _TREE_H_
#ifndef _OPERATEGRPADJMATRIX_H_
#define _OPERATEGRPADJMATRIX_H_

#include <iostream>
#include <queue>
#include <stack>
#include "grpAdjMatrix.h"
#include "tree.h"

using namespace std;

//定义边集(prim)
typedef struct minEdgeType{
    int v;             //边中已选顶点一端
    cellType eWeight;  //边的权重
} MinEdgeType;

//定义边集(kruskal)
typedef int eInfoType;
typedef struct edgetype{
    int vBeign;
    int vEnd;
    eInfoType eWeight;
}EdgeType;

//操作菜单
void menu()
{
    cout<<"*************************************************"<<endl;
    cout<<"0退出程序"<<endl;
    cout<<"1数据文件创建图"<<endl;
    cout<<"2打印出图(网)的两种遍历序"<<endl;
    cout<<"3求给定图中的边(或弧)的数目"<<endl;
    cout<<"4对给定的图G及出发点v0,设计算法从V0出发深度优先遍历图G,并构造出相应的生成树或生成森林"<<endl;
    cout<<"5对给定的图G及出发点v0,设计算法从V0出发广度优先遍历图G,并构造出相应的生成树或生成森林"<<endl;
    cout<<"6实现Prim算法,求图G的最小生成树"<<endl;
    cout<<"7实现Kruskal算法,求图G的最小生成树"<<endl;
    cout<<"8实现Dijkstra算法,求图G指定顶点到其余顶点之间的最短路径"<<endl;
    cout<<"9实现Floyd算法,求图G各顶点之间的最短路径"<<endl;
    cout<<"10求解图G的拓扑序列"<<endl;
    cout<<"11求解AOE网的关键路径"<<endl;
    cout<<"*************************************************"<<endl;
}
//连通图深度优先遍历
void DFS(Graph &G,int v)
{
    int w;
    visit(G,v);             //访问定点,并设置其访问标志
    w=firstAdj(G,v);        //求出v的第一个临结点,返回临结点编号w
    while(w!=0)             //还存在临结点
    {
        if(visited[w]==false && G.AdjMatrix[v][w]>=1 && G.AdjMatrix[v][w]<INF)//从来没有访问过的临结点进行深度遍历
            DFS(G,w);
        w=nextAdj(G,v,w);    //取下一个临结点
    }
}
//一般图的深度优先遍历
void DFSTraverse(Graph &G,int v)
{
    int i;
    for(i=1;i<=G.VerNum;i++)
    {
        visited[i]=false;       //初始化访问标志为false
    }
    for(v;v>=1;v--)             //编号1到v
    {
        if(visited[v]==false)   //循环选择未被访问的顶点
            DFS(G,v);           //每次循环遍历一个连通分量
    }
    for(v;v<=G.VerNum;v++)      //编号v到G.vernum
    {
        if(visited[v]==false)   //循环选择未被访问的顶点
            DFS(G,v);           //每次循环遍历一个连通分量
    }
}
//连通图的广度优先遍历
void BFS(Graph &G,int v)
{
    queue<int> Q;              //队列存放元素的编号
    int w;
    visit(G,v);                //访问定点,并设置其访问标志
    Q.push(v);                 //节点编号入队
    while(!Q.empty())
    {
        v=Q.front();
        Q.pop();
        w=firstAdj(G,v);
        while(w!=0)
        {
            if(!visited[w] && G.AdjMatrix[v][w]>=1 && G.AdjMatrix[v][w]<INF)
            {
                visit(G,w);
                Q.push(w);
            }
            w=nextAdj(G,v,w);
        }
    }
}
//一般图的广度优先遍历
void BFSTraverse(Graph &G,int v)
{
    int i;
    for(i=1;i<=G.VerNum;i++)
    {
        visited[i]=false;       //初始化访问标志为false
    }
    for(v;v>=1;v--)             //编号1到v
    {
        if(visited[v]==false)   //循环选择未被访问的顶点
            BFS(G,v);           //每次循环遍历一个连通分量
    }
    for(v;v<=G.VerNum;v++)      //编号v到G.vernum
    {
        if(visited[v]==false)   //循环选择未被访问的顶点
            BFS(G,v);           //每次循环遍历一个连通分量
    }
}
//深度优先遍历生成树
void DFSTree(Graph &G,int v,csTree&T)
{
    int j,w,first=1;    //first标记是否为根节点,初始化为1
    csNode *p,*q;
    q=T;
    visited[v]=1;
    w=firstAdj(G,v);
    while(w!=0)             //还存在临结点
    {
        if(!visited[w] && G.AdjMatrix[v][w]>=1 && G.AdjMatrix[v][w]<INF)
        {
            p=new csNode;
            p->firstChild=NULL;
            p->nextSibling=NULL;
            p->data=G.Data[w];
            if(first)           //(生成第一个孩子)
            {
                T->firstChild=p;
                first=0;
            }
            else{               //(生成节点的兄弟节点)
                q->nextSibling=p;
            }
            q=p;
            DFSTree(G,w,q);     //递归处理每个节点
        }
        w=nextAdj(G,v,w);
    }
}
//深度优先遍历生成森林
csTree DFSForest(Graph &G,csTree &T,int v)
{
    int i;
    csNode *p;
    csTree q;
    T=NULL;
    for(i=1;i<=G.VerNum;i++)    //初始化visited数组
    {
        visited[i]=0;
    }
    for(v;v>=1;v--)             //编号1到v
    {
        if(!visited[v] )
        {
            p=new csNode;
            p->firstChild=NULL;
            p->nextSibling=NULL;
            p->data=G.Data[v];
            if(!T)          //为根节点
            {
                T=p;
                q=T;
            }
            else{           //生成数根节点的兄弟节点,也就是其他树的根节点
                q->nextSibling=p;
            }
            q=p;
            DFSTree(G,v,p);
        }
    }
    for(v+=1;v<=G.VerNum;v++)   //编号v到G.vernum
    {
        if(!visited[v] )
        {
            p=new csNode;
            p->firstChild=NULL;
            p->nextSibling=NULL;
            p->data=G.Data[v];
            if(!T)          //为根节点
            {
                T=p;
                q=T;
            }
            else{           //生成数根节点的兄弟节点,也就是其他树的根节点
                q->nextSibling=p;
            }
            q=p;
            DFSTree(G,v,p);
        }
    }
    return T;
}
//广度优先遍历生成树
void BFSTree(Graph &G,csTree&T,int v)
{
    int i,w;
    bool first=true;            //标志变量,判断是否生成孩子节点
    csNode *t,*q,*p;
    queue<int> Q;
    if(!T)                      //生成树的根节点
    {
        T=new csNode;
        T->data=G.Data[v];
        visited[v]=true;
        T->firstChild=T->nextSibling=NULL;
    }
    p=T;
    Q.push(v);
    //对其他层节点操作
    while(!Q.empty())
    {
        v=Q.front(); //获取队头编号
        Q.pop();     //并出队
        w=firstAdj(G,v);
        first=true;  //循环i层时需要把first置为true,以便生成T->firstChild
        while(w!=0)
        {
            if(!visited[w]&& G.AdjMatrix[v][w]>=1 && G.AdjMatrix[v][w]<INF)
            {
                Q.push(w);             //第i层节点入队
                visited[w]=true;       //设置其访问标志
                q=new csNode;
                q->data=G.Data[w];
                q->firstChild=q->nextSibling=NULL;
                if(first)              //生成孩子节点
                {
                    p->firstChild=q;
                    first=false;
                }
                else{                   //生成兄弟节点
                    p->nextSibling=q;
                }
                p=q;
            }
            w=nextAdj(G,v,w);
        }
    }
}
//广度优先遍历生成森林
csTree BFSForest(Graph &G,csTree&T,int v)
{
    int i;
    csNode *p;
    csTree q;
    T=NULL;
    for(i=1;i<=G.VerNum;i++)    //初始化visited数组
    {
        visited[i]=0;
    }
    for(v;v>=1;v--)             //编号1到v
    {
        if(!visited[v] )
        {
            visited[v]=true;    //标记已访问
            p=new csNode;
            p->firstChild=NULL;
            p->nextSibling=NULL;
            p->data=G.Data[v];
            if(!T)              //为根节点
            {
                T=p;
                q=T;
            }
            else{                //生成数根节点的兄弟节点,也就是其他树的根节点
                q->nextSibling=p;
            }
            q=p;
            BFSTree(G,p,v);
        }
    }
    for(v+=1;v<=G.VerNum;v++)   //编号v到G.vernum
    {
        if(!visited[v] )
        {
            visited[v]=true;    //标记已访问
            p=new csNode;
            p->firstChild=NULL;
            p->nextSibling=NULL;
            p->data=G.Data[v];
            if(!T)               //为根节点
            {
                T=p;
                q=T;
            }
            else{               //生成数根节点的兄弟节点,也就是其他树的根节点
                q->nextSibling=p;
            }
            q=p;
            BFSTree(G,p,v);
        }
    }
    return T;
}
//判断两个顶点是否有边
bool HasEdge(Graph &G,int vBegin ,int vEnd,int &eWeight)
{
    int f=false;
    if(G.AdjMatrix[vBegin][vEnd]!=INF)
    {
        eWeight=G.AdjMatrix[vBegin][vEnd];
        f=true;
        return f;
    }
    else{
        eWeight=G.AdjMatrix[vBegin][vEnd];
        return f;
    }

}
//初始化候选边集
void initTE(Graph &G,MinEdgeType TE[],int vID)
{
    int i;
    int eWeight;
    for(i=1;i<=G.VerNum;i++)
    {
        //初始化数组
        if(HasEdge(G,vID,i,eWeight))   //  顶点和i有边
        {
            TE[i].v=vID;
            TE[i].eWeight=eWeight;
        }
        else{
            TE[i].eWeight=INF;
        }
    }
}
//得到候选边集的最小边
int getMinEdge(Graph &G,MinEdgeType TE[])
{
    int eMin=INF;
    int i,j=0;
    for(i=1;i<=G.VerNum;i++)
    {
        if(visited[i]==false && TE[i].eWeight<eMin)
        {
            j=i;
            eMin=TE[i].eWeight;
        }
    }
    return j;
}
//当顶点vID被选中变为已选顶点后,更新候选边集
void updateTE(Graph &G,MinEdgeType TE[],int vID)
{
    int i,j;
    int eWeight;
    for(i=1;i<=G.VerNum;i++)
    {
        if(visited[i]==false)
        {
            //检查vID与i之间是否有临边
            //若其权值更小,则更新(vID,i)的权值
            if(HasEdge(G,vID,i,eWeight) && eWeight<TE[i].eWeight)
            {
                TE[i].v=vID;
                TE[i].eWeight=eWeight;
            }
        }
    }
}
//输出最小生成树的边
void printEdge(Graph &G,MinEdgeType TE[],int vID)
{
    int i;
    for(i=1;i<=G.VerNum;i++)
    {
        if(i!=vID)   //注意TE[vID]是无效数据
        {
            cout<<"("<<G.Data[i]<<","<<G.Data[TE[i].v]<<")"<<" ";
        }
    }
}
//prim算法
void prim(Graph &G,int vID)
{
    MinEdgeType TE[MaxVerNum+1];    //候选边集
    //TE[i]=vID为起点
    int i;
    int curID;   //当前选择编号
    for(i=1;i<=G.VerNum;i++)
    {
        visited[i]=false;       //初始化访问标志为false
    }
    initTE(G,TE,vID);
    visited[vID]=true;
    for(i=1;i<G.VerNum;i++)  //循环选择n-1条边
    {
        curID=getMinEdge(G,TE);
        visited[curID]=true;
        updateTE(G,TE,curID);       //选择curID后,更新候选边集
    }
    printEdge(G,TE,vID);        //输出数组TE[]
}
//获取边
void getEdge(Graph &G,EdgeType edges[])
{
    int i,v;        //v是顶点编号
    int k=0;        //作为边数组下标
    for(i=1;i<=G.VerNum;i++)
    {
        v=firstAdj(G,i);    //获取顶点编号i的第一个关联顶点的编号
        while(v)
        {
            edges[k].vBeign=i;
            edges[k].vEnd=v;
            edges[k].eWeight=G.AdjMatrix[i][v];  //获取权重
            v=nextAdj(G,i,v);
            k++;
        }
    }
}
//获取边集edges[]的最小边
EdgeType getMinEdge(Graph &G,EdgeType edges[],int edgeUsed[],int &n)
{
    //n返回最小边的下标
    EdgeType minEdge;
    cellType wMin=INF;      //保存最小权值
    int i;
    int M;              //控制循环次数
    if(G.gKind==UDG || G.gKind==UDN)
    {
        M=G.ArcNum*2;   //无向网有效边数是原边数2倍
    }
    else{
        M=G.ArcNum;     //有向网
    }
    for(i=0;i<M;i++)
    {
        if(edgeUsed[i]==false && edges[i].eWeight<wMin)
        {
            //对未使用且权值最小的边,暂定为最小边
            wMin=edges[i].eWeight;
            minEdge.eWeight=edges[i].eWeight;
            minEdge.vBeign=edges[i].vBeign;
            minEdge.vEnd=edges[i].vEnd;
            n=i;
        }
    }
    return minEdge;   //返回最小边
}
//输出树边
void printTreeEdges(Graph &G,EdgeType treeEdges[])
{
    int i;
    for(i=0;i<G.VerNum-1;i++)
    {
        cout<<"("<<G.Data[treeEdges[i].vBeign]<<","<<G.Data[treeEdges[i].vEnd]<<")"<<" ";
    }
}
//kruskal算法
void Kruskal(Graph &G)
{
    int conVerID[MaxVerNum];                //顶点的连通分量编号数组
    EdgeType edges[MaxVerNum*MaxVerNum];    //存放所有边集
    EdgeType treeEdges[MaxVerNum];          //存放n-1条树边
    int edgeUsed[MaxVerNum*MaxVerNum];      //标记edges[]中的边是否用过,用过得1
    EdgeType minEdge;
    int i,j;
    int k=0;
    int conID;                              //边的终止顶点vEnd的2连通分量编号
    int n;                                  //返回最小边的下标
    getEdge(G,edges);                       //获取所有边信息
    //初始化可用边标记数组
    int M;                                  //循环次数
     if(G.gKind==UDG || G.gKind==UDN)
    {
        M=G.ArcNum*2;                       //无向网有效边数是原边数2倍
    }
    else{
        M=G.ArcNum;                         //有向网
    }
    for(i=0;i<M;i++)
    {
        edgeUsed[i]=false;                  //标记所有边可用
    }
    //初始化连通分量编号
    for(i=1;i<=G.VerNum;i++)
    {
        conVerID[i-1]=i;                    //注意编号与数组差1
    }
    //取n-1条边构成生成树(核心代码)
    for(i=1;i<G.VerNum;i++)
    {
        minEdge=getMinEdge(G,edges,edgeUsed,n); //获取最小边
        //形成回路
        while(conVerID[minEdge.vBeign-1]==conVerID[minEdge.vEnd-1])
        {
            edgeUsed[n]=1;                   //标记最小边不可用
            minEdge=getMinEdge(G,edges,edgeUsed,n);//继续取下一条最小边
        }
        //至此取的一条最小可用边
        treeEdges[i-1]=minEdge,              //加入树边
        conID=conVerID[minEdge.vEnd-1];      //取得最小边的终点编号
        for(j=1;j<=G.VerNum;j++)
        {
            if(conVerID[j-1]==conID)
            {
                conVerID[j-1]=conVerID[minEdge.vBeign-1];
            }
        }
        edgeUsed[n]=true;                   //标记当前选择的边已用过
    }
    printTreeEdges(G,treeEdges);
}
//Dijkstra算法
void Dijkstra(Graph &G,int path[],int dist[],int vID)
{
    int solved[MaxVerNum];      //标记顶点是否已经求出最短路径
    int i,j,v;
    cellType minDist;           //最短距离
    //初始化sloved[]和dist[]数组
    for(i=1;i<=G.VerNum;i++)
    {
        solved[i-1]=0;          //标记所有节点均未求解
        dist[i-1]=G.AdjMatrix[vID][i];
        if(dist[i-1]!=INF)
        {
            path[i-1]=vID;      //第i顶点的前驱节点为vID
        }
        else{
            path[i-1]=-1;       //无前驱节点
        }
    }
    solved[vID-1]=1;            //标记vID已求解
    dist[vID-1]=0;              //到自身距离为0
    path[vID-1]=-1;             //vID为起始顶点,无前驱
    //依次找到其他n-1个顶点
    for(i=1;i<=G.VerNum;i++)
    {
        minDist=INF;
        //在未求解顶点中寻找距离vID最近的顶点
        for(j=1;j<=G.VerNum;j++)
        {
            if(solved[j-1]==0 && dist[j-1]<minDist)
            {
                v=j;
                minDist=dist[j-1];
            }
        }
        if(minDist==INF)
            return;
        //输出本次选择的顶点距离
        cout<<"选择顶点"<<G.Data[v]<<"--距离:"<<minDist<<endl;
        solved[v-1]=1;          //顶点已找到最短距离,标记已解顶点
        //修改距离
        for(j=1;j<=G.VerNum;j++)
        {
            if(solved[j-1]==0 && (minDist+G.AdjMatrix[v][j]<dist[j-1]))
            {
                //更新j到顶点vID的最短距离
                dist[j-1]=minDist+G.AdjMatrix[v][j];
                path[j-1]=v;      //更新顶点j的直接前驱为顶点v
            }
        }
    }
}
//输出Dijkstra路径
void printDijsktra(Graph &G,int path[],int dist[],int vID)
{
    int sPath[MaxVerNum];       //保存各个顶点到vID的路径
    int vPre;                   //前驱节点编号
    int top=-1;
    int i,j;
    for(i=1;i<=G.VerNum;i++)
    {
        cout<<G.Data[vID]<<"到"<<G.Data[i];
        if(dist[i-1]==INF)
        {
            cout<<"无路径可到达"<<endl;
        }
        else{
            cout<<"最短距离为:"<<dist[i-1]<<endl;
            cout<<"路径:";
        }
        top++;
        sPath[top]=i;
        vPre=path[i-1];
        while(vPre!=-1)
        {
            top++;
            sPath[top]=vPre;
            vPre=path[vPre-1];
        }
        if(dist[i-1]!=INF)
        {
            for(j=top;j>=0;j--)
            {
                cout<<G.Data[sPath[j]]<<" ";
            }
        }
        top=-1;
        cout<<endl;
    }
}
//Floyd算法
void floyd(Graph &G,cellType dist[MaxVerNum][MaxVerNum],int path[MaxVerNum][MaxVerNum])
{
    int i,j,m;
    for(i=1;i<=G.VerNum;i++)
    {
        for(j=1;j<=G.VerNum;j++)
        {
            dist[i-1][j-1]=G.AdjMatrix[i][j];
            if(i!=j && G.AdjMatrix[i][j]<INF)
            {
                path[i-1][j-1]=i;
            }
            else{
                path[i-1][j-1]=-1;
            }
        }
    }
    //floyd核心算法,三重循环
    for(m=1;m<=G.VerNum;m++)
    {
        for(i=1;i<=G.VerNum;i++)
        {
            for(j=1;j<=G.VerNum;j++)
            {
                if(i!=j && dist[i-1][m-1]+dist[m-1][j-1] < dist[i-1][j-1])
                {
                    dist[i-1][j-1]=dist[i-1][m-1]+dist[m-1][j-1];
                    path[i-1][j-1]=path[m-1][j-1];
                }
            }
        }
    }
}
//输出floyd路径
void printFloyd(Graph &G,cellType dist[MaxVerNum][MaxVerNum],int path[MaxVerNum][MaxVerNum])
{
    int i,j,k;
    int Path[MaxVerNum];
    int vPre;         //保存前驱节点编号
    int top=-1;       //数组有效元素的最大下标
    for(i=1;i<=G.VerNum;i++)
    {
        for(j=1;j<=G.VerNum;j++)
        {
            if(i!=j)
            {
                cout<<G.Data[i]<<"到"<<G.Data[j]<<endl;
                if(dist[i-1][j-1]==INF)
                {
                    cout<<"无路径可到达"<<endl;
                }
                else{
                   cout<<"最短距离为:"<<dist[i-1][j-1]<<endl;
                   cout<<"路径为:";
                }
                if(dist[i-1][j-1]!=INF)
                {
                    top++;
                    Path[top]=j;
                    vPre=path[i-1][j-1];
                    while(i!=vPre && vPre!=-1)
                    {
                        top++;
                        Path[top]=vPre;
                        vPre=path[i-1][vPre-1];
                    }
                    top++;
                    Path[top]=vPre;
                    for(k=top;k>=0;k--)
                    {
                        cout<<G.Data[Path[k]]<<" ";
                    }
                    cout<<endl;
                }
                top=-1;
            }
        }
        top=-1;
        cout<<endl;
    }
}
//获取所有顶点的入度并保存在inds[]中
void getInDegree(Graph &G,int inds[])
{
    int i,j;
    int k=0;    //记录入度数
    for(i=1;i<=G.VerNum;i++)
    {
        for(j=1;j<=G.VerNum;j++)
        {
            if(G.AdjMatrix[j][i]>0 && G.AdjMatrix[j][i]<INF)
            {
                k++;
            }
        }
        inds[i]=k;
        k=0;        //再次初始化为0
    }
}
//拓扑排序
int TopologicalSort(Graph &G,int topoList[],int vet[])
{
    //topoList[]数组用于存放拓扑序列
    int inds[MaxVerNum];       //定义顶点入度数组
    stack<int> S;              //定义一个顺序栈,保存入度为0的节点
    int i;
    int v;                     //顶点编号
    int vCount=0;              //记录顶点入度为0的顶点数
    for(i=1;i<=G.VerNum;i++)    //初始化vet[]数组
    {
        vet[i]=0;
    }
    for(i=1;i<=G.VerNum;i++)    //入度数组初始化,inds[0]不用
    {
        inds[i]=0;
    }
    for(i=1;i<G.VerNum;i++)    //拓扑排序数组初始化
    {
        topoList[i-1]=-1;      //编号初始化为-1
    }
    getInDegree(G,inds);       //获取所有顶点的入度并保存在inds[]中
    for(i=1;i<=G.VerNum;i++)  //入度为0节点入栈
    {
        if(inds[i]==0)
        {
            S.push(i);
        }
    }
    while(!S.empty())
    {
        v=S.top();          //或取栈顶元素
        S.pop();            //出栈
        topoList[vCount]=v; //当前入度为0的顶点v,加入拓扑序列
        vCount++;
        for(i=1;i<=G.VerNum;i++)
        {
            if(G.AdjMatrix[v][i]>=1 && G.AdjMatrix[v][i]<INF)
            {
                //与v邻接的顶点i入度减1
                if(!(--inds[i]))//顶点i的入度已经为0,入栈
                {
                    S.push(i);
                }
                 if(vet[v]+G.AdjMatrix[v][i] > vet[i])
                {
                      vet[i]=vet[v]+G.AdjMatrix[v][i];  //求其v的邻接顶点最早发生时间
                }
            }
        }
    }
    if(vCount==G.VerNum)
        return 1;   //返回无回路标记
    else
        return 0;
}
//输出拓扑序列
void printTopoList(Graph &G,int topoList[],int vet[])
{
    int i;
    if(TopologicalSort(G,topoList,vet))
    {
        cout<<"拓扑序列为:";
        for(i=0;i<G.VerNum;i++)
        {
            cout<<G.Data[topoList[i]]<<" ";
        }
        for(i=0;i<G.VerNum;i++)
        {
            cout<<endl;
            cout<<"编号"<<G.Data[topoList[i]]<<"最早发生时间:"<<vet[topoList[i]];
        }
    }
    else{
        cout<<"有有向环,不能生成拓扑序列!"<<endl;
    }
}
//获取所有顶点的出度并保存数组outds[]中
void getOutDegree(Graph &G,int outds[])
{
    int i,j;
    int k=0;    //记录出度数
    for(i=1;i<=G.VerNum;i++)
    {
        for(j=1;j<=G.VerNum;j++)
        {
            if(G.AdjMatrix[i][j]>0 && G.AdjMatrix[i][j]<INF)
            {
                k++;
            }
        }
        outds[i]=k;
        k=0;        //再次初始化为0
    }
}
//逆拓扑排序
int antiTopologicalSort(Graph &G,int vlt[],int vet[])
{
    int outds[MaxVerNum];       //定义顶点出度数组
    stack<int> S;               //保存出度为0的顶点
    int i;
    int v;                      //顶点编号
    int vCount=0;               //记录顶点入度为0的顶点数
    int max=0;
    for(i=1;i<=G.VerNum;i++)
    {
        if(max<vet[i])
        {
            max=vet[i];         //获取最大时间(汇点时间)
        }
    }
    for(i=1;i<=G.VerNum;i++)
    {
        vlt[i]=max;              //全部赋值(汇点时间)
    }
    for(i=1;i<=G.VerNum;i++)    //出度数组初始化。outds[0]不用
    {
        outds[i]=0;
    }
//    for(i=1;i<G.VerNum;i++)    //拓扑排序数组初始化
//    {
//        antiTopoList[i-1]=-1;      //编号初始化为-1
//    }
    getOutDegree(G,outds);      //获取所有顶点的出度并保存数组outds[]中
    for(i=1;i<=G.VerNum;i++)    //出度为0节点入栈
    {
        if(outds[i]==0)
        {
            S.push(i);
        }
    }
    while(!S.empty())
    {
        v=S.top();              //获取栈顶元素
        S.pop();                //出栈
    //  antiTopoList[vCount]=v; //当前出度为0的顶点v,加入拓扑序列
        vCount++;
        for(i=1;i<=G.VerNum;i++)
        {
            if(G.AdjMatrix[i][v]>=1 && G.AdjMatrix[i][v]<INF)
            {
                //邻接v的顶点的出度减1
                if(!(--outds[i]))
                {
                    S.push(i);  //出度为0的顶点入栈
                }
                if(vlt[v]-G.AdjMatrix[i][v] < vlt[i])
                {
                    vlt[i]=vlt[v]-G.AdjMatrix[i][v];    //求其v上一个顶点的最迟发生时间
                }
            }
        }
    }
    if(vCount==G.VerNum)
        return 1;   //返回无回路标记
    else
        return 0;
}
//输出逆拓扑排序
void printAntiTopoList(Graph &G,int topoList[],int vlt[],int vet[])
{
    int i;
    if(antiTopologicalSort(G,vlt,vet))
    {
        cout<<"拓扑序列为:";
        for(i=0;i<G.VerNum;i++)
        {
            cout<<G.Data[topoList[i]]<<" ";
        }
        for(i=0;i<G.VerNum;i++)
        {
            cout<<endl;
            cout<<"编号"<<G.Data[topoList[i]]<<"最晚发生时间:"<<vlt[topoList[i]];
        }
    }
    else{
        cout<<"有有向环,不能生成逆拓扑序列!"<<endl;
    }
}
//输出一条关键路径
void printCriticalPath(Graph &G,int topoList[],int vlt[],int vet[])
{
    int i=0,j=0,k=0,v=0;
    int vPre=0;
    if(!TopologicalSort(G,topoList,vet))
    {
        cout<<"无拓扑序列!"<<endl;
        return ;
    }
    cout<<"关键路径为:";
    i=G.VerNum;
    k=topoList[v];
    while(k!=vPre)          //如上一次访问顶点编号与此次相同则退出
    {
        if(vet[k]==vlt[k])
        {
            if(k!=vPre)
            {
                cout<<G.Data[k]<<" ";       //不同则输出
            }
            vPre=k;
            for(j=1;j<=G.VerNum;j++)
            {
                if(G.AdjMatrix[k][j]>=1 && G.AdjMatrix[k][j] < INF)
                {
                    if(vet[j]==vlt[j])
                    {
                        break;
                    }
                }
            }
        }
        k=j;    //或取k的邻接点
    }
}
#endif // _OPERATEGRPADJMATRIX_H_
#include <iostream>
#include <Cstdlib>
#include "createGrpAdjMatrix.h"
#include "operateGrpAdjMatrix.h"
#include "tree.h"

using namespace std;

int main()
{
    int i,x;
    Graph G;
    csTree T;
    int path[MaxVerNum];
    int dist[MaxVerNum];
    int topoList[MaxVerNum];        //拓扑序列
    int antiTopoList[MaxVerNum];    //逆拓扑序列
    cellType Dist[MaxVerNum][MaxVerNum];
    int Path[MaxVerNum][MaxVerNum];
    int vet[MaxVerNum]={0};         //事件的最早发生时间
    int vlt[MaxVerNum]={0};         //事件的最晚发生时间
    char fileName[100];         //保存文件名
    menu();
    cout<<"请输入执行序号:";
    cin>>i;
    while(i)
    {
        switch(i)
        {
            case 1:
                cout<<"请输入打开的文件名:";
                cin>>fileName;
                if(CreateGrpFromFile(fileName,G))
                {
                        cout<<"数据处理完毕!"<<endl;
                }
            break;
            case 2:
                cout<<"请输入访问图的起始顶点编号:";
                cin>>x;
                cout<<"深度优先遍历序为:";
                DFSTraverse(G,x);
                cout<<endl;
                cout<<"广度优先遍历序为:";
                BFSTraverse(G,x);
                cout<<endl;
            break;
            case 3:
                cout<<"边或弧的数目为:"<<G.ArcNum;
                cout<<endl;
            break;
            case 4:
                T=NULL;
                cout<<"请输入访问图的起始顶点编号:";
                cin>>x;
                T=DFSForest(G,T,x);
                cout<<"树或森林的先序遍历序为:";
                perOrderTraverse(T);
                cout<<endl;
                destroy(T);
            break;
            case 5:
                T=NULL;
                cout<<"请输入访问图的起始顶点编号:";
                cin>>x;
                T=BFSForest(G,T,x);
                cout<<"树或森林的先序遍历序为:";
                perOrderTraverse(T);
                cout<<endl;
                destroy(T);
            break;
            case 6:
                cout<<"请输入访问图的起始顶点编号:";
                cin>>x;
                prim(G,x);
                cout<<endl;
            break;
            case 7:
                cout<<"Kruskal最小生成树为:";
                Kruskal(G);
                cout<<endl;
            break;
            case 8:
                cout<<"请输入访问图的起始顶点编号:";
                cin>>x;
                Dijkstra(G,path,dist,x);
                printDijsktra(G,path,dist,x);
            break;
            case 9:
                floyd(G,Dist,Path);
                printFloyd(G,Dist,Path);
            break;
            case 10:
                printTopoList(G,topoList,vet);
                cout<<endl;
                printAntiTopoList(G,topoList,vlt,vet);
                cout<<endl;
            break;
            case 11:
                TopologicalSort(G,topoList,vet);
                antiTopologicalSort(G,vlt,vet);
                printCriticalPath(G,topoList,vlt,vet);
                cout<<endl;
            break;
        }
        system("PAUSE");
        system("CLS");
        menu();
        cout<<"请输入执行序号:";
        cin>>i;
    }
    return 0;
}

五、运行和测试

本实验所需文件和代码可从百度网盘进行下载:https://pan.baidu.com/s/19Rcf5faJNDj8NFC74hlcrA  提取码:y5ap

发布了46 篇原创文章 · 获赞 48 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_39559641/article/details/89070077