#include <iostream>
#include <queue>
#include <stack>
using namespace std;
typedef char vertextype; //顶点数据类型
typedef int adjtype; //权值类型
/邻接矩阵存储结构//
#define MAXVAL 99999 //设最大值
#define MAXNUM 20 //最大顶点个数
struct MGraph
{
vertextype vex[MAXNUM];//用一维数组表示顶点
adjtype arcs[MAXNUM][MAXNUM];//用二维数组表示邻接矩阵
int n;//图的当前顶点数
int e;//图的当前边数
};//邻接矩阵
///邻接表存储结构/
#define M 50
struct node
{
int adjvex;//邻接点域
node *link;//指针域4
adjtype info;//权值信息
};
struct headnode
{
vertextype vexdata;//顶点数据域
node *firstarc;//指针指向链表中第一个节点
};
struct ALGraph
{
headnode adjlist[M];
int n;//顶点个数
};//邻接表
void dispgraph(ALGraph ALG);//打印图邻接表
void dispgraph_N(ALGraph ALN);//打印网邻接表
无向图函数
void CreatUDG_M(MGraph &MG);
void CreatUDG_ALG(ALGraph &ALG);
void DFS(ALGraph ALG);
void BFS(ALGraph ALG);
无向网函数
void CreatUDN_M(MGraph &MN);
void CreatUDN_ALG(ALGraph &ALN);
void Mini_PRIM(MGraph MN);
void Mini_KRASKAL(MGraph MN);
有向图函数
void CreatDG_M(MGraph &MN);
void CreatDG_ALG(ALGraph &ALN);
void Topo_Sort(ALGraph ALN);
有向网函数
void CreatDN_M(MGraph &MN);
void CreatDN_ALN(ALGraph &ALN);
void Criticla_Path(ALGraph ALN);
void Shortest_Path(MGraph MN);
void ShowMainMenu()
{
cout<<"/n";
cout<<" ***************图的基本操作及应用******************/n";
cout<<" * 1 无向图的基本操作及应用 */n";
cout<<" * 2 无向网的基本操作及应用 */n";
cout<<" * 3 有向图的基本操作及应用 */n";
cout<<" * 4 有向网的基本操作及应用 */n";
cout<<" * 5 退出 */n";
cout<<" ***************************************************/n";
}
void UDG()//无向图
{
MGraph MG;//邻接矩阵存储
ALGraph ALG;//邻接表存储
int n;
do
{
cout<<"/n";
cout<<" ***************无向图的基本操作及应用**************/n";
cout<<" * 1 创建无向图的邻接矩阵 */n";
cout<<" * 2 创建无向图的邻接表 */n";
cout<<" * 3 无向图的深度优先遍历 */n";
cout<<" * 4 无向图的广度优先遍历 */n";
cout<<" * 5 退出 */n";
cout<<" ***************************************************/n";
cout<<"请选择操作:";
cin>>n;
switch(n)
{
case 1:
CreatUDG_M(MG);//创建无向图的邻接矩阵
break;
case 2:
CreatUDG_ALG(ALG);//创建无向图的邻接表
dispgraph(ALG);//打印邻接表
break;
case 3:
DFS(ALG);//无向图的深度优先遍历
break;
case 4:
BFS(ALG);//无向图的广度优先遍历
break;
default:
if (n!=5)
cout<<"错误,重新输入/n";
}
}while(n!=5);
}
void UDN()//无向网
{
MGraph MN;
ALGraph ALN;
int n;
do{
cout<<"/n";
cout<<" ***************无向网的基本操作及应用**************/n";
cout<<" * 1 创建无向网的邻接矩阵 */n";
cout<<" * 2 创建无向网的邻接表 */n";
cout<<" * 3 prim算法求最小生成树 */n";
cout<<" * 4 kraskal算法求最小生成树 */n";
cout<<" * 5 退出 */n";
cout<<" ***************************************************/n";
cout<<"请选择操作:";
cin>>n;
switch(n)
{
case 1:
CreatUDN_M(MN);//创建无向网的邻接矩阵
break;
case 2:
CreatUDN_ALG(ALN);//创建无向网的邻接表
dispgraph_N(ALN);//打印无向网邻接表
break;
case 3:
Mini_PRIM(MN);//prim算法求最小生成树
break;
case 4:
Mini_KRASKAL(MN);//kraskal算法求最小生成树
break;
default:
if (n!=5)
cout<<"错误,重新输入/n";
}
}while(n!=5);
}
void DG()//有向图
{
MGraph MG;//邻接矩阵存储
ALGraph ALG;//邻接表存储
int n;
do
{
cout<<"/n";
cout<<" ***************有向图的基本操作及应用**************/n";
cout<<" * 1 创建有向图的邻接矩阵 */n";
cout<<" * 2 创建有向图的邻接表 */n";
cout<<" * 3 拓扑排序 */n";
cout<<" * 4 退出 */n";
cout<<" ***************************************************/n";
cout<<"请选择操作:";
cin>>n;
switch(n)
{
case 1:
CreatDG_M(MG);
break;
case 2:
CreatDG_ALG(ALG);
dispgraph(ALG);
break;
case 3:
Topo_Sort(ALG);
break;
default:
if (n!=4)
cout<<"错误,重新输入/n";
}
}while(n!=4);
}
void DN()//有向网
{
MGraph MN;
ALGraph ALN;
int n;
do{
cout<<"/n";
cout<<" ***************有向网的基本操作及应用**************/n";
cout<<" * 1 创建有向网的邻接矩阵 */n";
cout<<" * 2 创建有向网的邻接表 */n";
cout<<" * 3 关键路径 */n";
cout<<" * 4 单源顶点最短路径问题 */n";
cout<<" * 5 退出 */n";
cout<<" ***************************************************/n";
cout<<"请选择操作:";
cin>>n;
switch(n)
{
case 1:
CreatDN_M(MN);//创建有向网的邻接矩阵
break;
case 2:
CreatDN_ALN(ALN);//创建有向网的邻接表
dispgraph_N(ALN);//打印有向网邻接表
break;
case 3:
Criticla_Path(ALN);//关键路径
break;
case 4:
Shortest_Path(MN);//最短路径
break;
default:
if (n!=5)
cout<<"错误,重新输入/n";
}
}while(n!=5);
}
void main()
{
int n;
do{
ShowMainMenu();
cout<<"请选择操作:";
cin>>n;
switch(n){
case 1:
UDG();//无向图
break;
case 2:
UDN();//无向网
break;
case 3:
DG();//有向图
break;
case 4:
DN();//有向网
break;
default:
if (n!=5)
cout<<"错误,重新输入/n";
}
}while(n!=5);
}
//
void dispgraph(ALGraph ALG)//打印图邻接表
{
int i;
node *p;
for(i=1;i<=ALG.n;i++)
{
cout <<ALG.adjlist[i].vexdata;
p = ALG.adjlist[i].firstarc;
while(p != NULL)
{
cout <<" --";
cout << ALG.adjlist[p->adjvex].vexdata;
p=p->link;
}
cout << endl;
}
}
void dispgraph_N(ALGraph ALN)//打印网邻接表
{
int i;
node *p;
for(i=1;i<=ALN.n;i++)
{
cout <<ALN.adjlist[i].vexdata;
p = ALN.adjlist[i].firstarc;
while(p != NULL)
{
cout <<" --";
cout << ALN.adjlist[p->adjvex].vexdata <<"("<<p->info<<")";
p=p->link;
}
cout << endl;
}
}
无向图函数
void CreatUDG_M(MGraph &MG)
{
int i,j,k;
cout <<"输入顶点数和边数:";
cin >>MG.n>>MG.e;//输入图的顶点数和边数
cout << "输入顶点:";
for(i=1;i<=MG.n;i++)
cin >> MG.vex[i];//构造顶点向量
for(i=1;i<=MG.n;i++)
for(j=1;j<=MG.n;j++)
MG.arcs[i][j]=0;//初始化邻接矩阵
for(k=1;k<=MG.e;k++)
{
cout<<"输入一条边依附的顶点的序号:";
cin>>i>>j;//输入一条边依附的顶点的序号及权值
MG.arcs[i][j]=1;
MG.arcs[j][i]=1;//权值赋予邻接矩阵相应元素
}
}
void CreatUDG_ALG(ALGraph &ALG)
{
node *p;
int i,j;
char ch;
cout << "输入顶点数:";
cin >> ALG.n;
cout <<"输入顶点信息:";
for(i=1;i<=ALG.n;i++)
{
cin >> ch;//读入顶点信息
ALG.adjlist[i].vexdata = ch;//设置顶点为字符型
ALG.adjlist[i].firstarc =NULL;//将链表初始化为空
}
cout << "读入一条边依附的顶点序号:";
cin >> i >> j;
while((i>0)&&(j>0))//输入(i,j)为(0,0)作结束标记
{
p = new node;//生成邻接点序号为j的表结点
p->adjvex = j;
p->link = ALG.adjlist[i].firstarc;
ALG.adjlist[i].firstarc = p;//结点j插入到第i个链表
p = new node;//生成邻接点序号为i的表结点
p->adjvex = i;
p->link = ALG.adjlist[j].firstarc;
ALG.adjlist[j].firstarc = p;//结点i插入到第j个链表
cout << "读入一条边依附的顶点序号:";
cin >> i >> j;
}
}
void dfs(ALGraph ALG,int v,int flag[])
{
node *p;
int i;
flag[v] = 1;
cout << ALG.adjlist[v].vexdata << endl;//访问顶点i
p = ALG.adjlist[v].firstarc;//p指向v的第一个邻接点
while(p != NULL)
{
i = p->adjvex;//取出p指针所指的邻接点序号
if(flag[i] == 0)
dfs(ALG,i,flag);//对尚未访问的邻接点递归调用dfs算法
p = p->link;//查找下一个邻接点
}
}
void DFS(ALGraph ALG)
{
int i;
int flag[M];
for(i = 1;i<=ALG.n;i++)
flag[i] = 0;//初始化标志数组
cout << "输入顶点序号:";
cin>>i;
dfs(ALG,i,flag);//以i为顶点深度优先遍历
}
void bfs(ALGraph ALG,int v,int flag[])
{
queue <int> q;//q为辅助队列
node *p;
cout << ALG.adjlist[v].vexdata << endl;//访问顶点v
flag[v] = 1;
q.push(v);//刚访问过的顶点序列入队列
while(!q.empty())//当队列不为空时
{
v=q.front();//访问过的顶点值传给v
q.pop();//顶点出队列
p = ALG.adjlist[v].firstarc;//p指向第一个邻接点
while(p != NULL)
{
v = p ->adjvex;
if(flag[v] == 0)//如果未访问
{
flag[v] = 1;//设为访问
cout << ALG.adjlist[v].vexdata << endl;//访问顶点
q.push(v);//被访问过的顶点入队列
}
p = p->link;//查找下一个邻接点
}
}
}
void BFS(ALGraph ALG)
{
int i;
int flag[M];//定义标志数组
for(i=1;i<=ALG.n;i++)//初始化标志数组
flag[i] = 0;
cout << "输入顶点序号:";
cin>>i;
bfs(ALG,i,flag);//以i为顶点广度深度优先遍历
}
无向网函数
void CreatUDN_M(MGraph &MN)
{
int i,j,k;
int w;
cout <<"输入顶点数和边数:";
cin >>MN.n>>MN.e;//输入图的顶点数和边数
cout << "输入顶点:";
for(i=1;i<=MN.n;i++)
cin >> MN.vex[i];//构造顶点向量
for(i=1;i<=MN.n;i++)
for(j=1;j<=MN.n;j++)
MN.arcs[i][j]=MAXVAL;//初始化邻接矩阵
for(k=1;k<=MN.e;k++)
{
cout<<"输入一条边依附的顶点的序号及权值:";
cin>>i>>j>>w;//输入一条边依附的顶点的序号及权值
MN.arcs[i][j]=w;
MN.arcs[j][i]=w;//权值赋予邻接矩阵相应元素
}
}
void CreatUDN_ALG(ALGraph &ALN)
{
node *p;
int i,j,k;
char ch;
cout << "输入顶点数:";
cin >> ALN.n;
cout <<"输入顶点信息:";
for(i=1;i<=ALN.n;i++)
{
cin >> ch;//读入顶点信息
ALN.adjlist[i].vexdata = ch;//设置顶点为字符型
ALN.adjlist[i].firstarc =NULL;//将链表初始化为空
}
cout << "读入一条边依附的顶点序号及权值:";
cin >> i >> j >> k;
while((i>0)&&(j>0))//输入(i,j)为(0,0)作结束标记
{
p = new node;//生成邻接点序号为j的表结点
p->info = k;
p->adjvex = j;
p->link = ALN.adjlist[i].firstarc;
ALN.adjlist[i].firstarc = p;//结点j插入到第i个链表
p = new node;//生成邻接点序号为i的表结点
p->info = k;
p->adjvex = i;
p->link = ALN.adjlist[j].firstarc;
ALN.adjlist[j].firstarc = p;//结点i插入到第j个链表
cout << "读入一条边依附的顶点序号及权值:";
cin >> i >> j >> k;
}
}
void Mini_PRIM(MGraph MN)
{
struct//辅助数组
{
int adjvex;//记录前驱顶点序号
int lowcost;
}closedge[M];
int k;
cout << "输入根的序号:";
cin >> k;
int i,j,p,v;
int min;
for(i = 1; i<=MN.n;i++)//辅助数组初始化
if(i != k)
{
closedge[i].adjvex = k;
closedge[i].lowcost = MN.arcs[k][i];
}
closedge[k].lowcost = 0;
for(i = 1; i < MN.n; i++)//进行n-1次循环,每次求出最小生成树的第j条边
{
p = i;
min = MAXVAL;
for(v =1; v <= MN.n; v++)//选最小权值及对应的顶点
if((closedge[v].lowcost != 0)&&(closedge[v].lowcost < min))
{
min = closedge[v].lowcost;
p = v;
}
cout <<"<"<< MN.vex[closedge[p].adjvex] <<","<< MN.vex[p] <<"> "<< min <<endl;//输出最小边及权值
closedge[p].lowcost = 0;//将顶点p加到生成树上
for(j = 1; j <= MN.n; j++)
if(MN.arcs[p][j] < closedge[j].lowcost)
{
closedge[j].lowcost = MN.arcs[p][j];//修改未选出点的最小权值
closedge[j].adjvex = p;//记下在生成树一端的顶点序号,新顶点并入生成树
}
}
}
void Mini_KRASKAL(MGraph MN)
{
int a[M];//顶点辅助值,用来判断是否连成回路
int i,j,k,p=1,q=1;
int count=1;
int min;//记录最小边
for(i = 1; i <= MN.n; i++)//初始化辅助值
a[i] =i;
while(count < MN.n)//选出n-1条边
{
min=MAXVAL;
for(j = 1;j<=MN.n;j++)
{
for(k=1;k<=MN.n;k++)
{
if((MN.arcs[j][k] != 0) && (MN.arcs[j][k] < min))
{
if(a[j]!=a[k])//判断是否会构成回路
{
min = MN.arcs[j][k];
p = j;
q = k;
}
}
}
}
MN.arcs[p][q] = 0;//
MN.arcs[q][p] = 0;//选中的边权值置为0
int m=a[p];
for(i=1;i<MN.n;i++)//将连接在一起的顶点辅助值改为相同
if(a[i]==m)
a[i]=a[q];
count++;
cout <<"<"<< MN.vex[p] <<","<< MN.vex[q] <<"> "<<min<<endl;//输出选中的边的顶点及权值
}
}
有向图函数
void CreatDG_M(MGraph &MG)
{
int i,j,k;
cout <<"输入顶点数和边数:";
cin >>MG.n>>MG.e;//输入图的顶点数和边数
cout << "输入顶点:";
for(i=1;i<=MG.n;i++)
cin >> MG.vex[i];//构造顶点向量
for(i=1;i<=MG.n;i++)
for(j=1;j<=MG.n;j++)
MG.arcs[i][j]=0;//初始化邻接矩阵
for(k=1;k<=MG.e;k++)
{
cout<<"输入一条边依附的顶点的序号:";
cin>>i>>j;//输入一条边依附的顶点的序号及权值
MG.arcs[i][j]=1;//权值赋予邻接矩阵相应元素
}
}
void CreatDG_ALG(ALGraph &ALG)
{
node *p;
int i,j;
char ch;
cout << "输入顶点数:";
cin >> ALG.n;
cout <<"输入顶点信息:";
for(i=1;i<=ALG.n;i++)
{
cin >> ch;//读入顶点信息
ALG.adjlist[i].vexdata = ch;//设置顶点为字符型
ALG.adjlist[i].firstarc =NULL;//将链表初始化为空
}
cout << "读入一条边依附的顶点序号:";
cin >> i >> j;
while((i>0)&&(j>0))//输入(i,j)为(0,0)作结束标记
{
p = new node;//生成邻接点序号为j的表结点
p->adjvex = j;
p->link = ALG.adjlist[i].firstarc;
ALG.adjlist[i].firstarc = p;//头插法将结点j插入到第i个链表
cout << "读入一条边依附的顶点序号:";
cin >> i >> j;
}
}
void InDegree(ALGraph ALG,int degree[])//求个顶点的入度
{
node *p;
int i,k;
for(i=1;i<=ALG.n;i++)
{
p = ALG.adjlist[i].firstarc;
while(p != NULL)
{
k = p->adjvex;
degree[k]++;
p=p->link;
}
}
}
void Topo_Sort(ALGraph ALG)
{
int i,m,k;
int degree[M];
for(i=1;i<=ALG.n;i++)
degree[i] = 0;//入度初始化为0
InDegree(ALG,degree);
stack <int> S;
for(i=1;i<=ALG.n;i++)
if(degree[i] == 0)
S.push(i);
int count=0;//对输出顶点计数
while(!S.empty())
{
m=S.top();
S.pop();
cout<< ALG.adjlist[m].vexdata << endl;//输出入度为0的顶点
++count;//计数
for(node *p = ALG.adjlist[m].firstarc;p != NULL; p=p->link)
{
k = p->adjvex;
if((--degree[k]) == 0)//若入度减为0,则入栈
S.push(k);
}
}
if(count < ALG.n)
cout << "该有向图有回路!";
}
有向网函数///
void CreatDN_M(MGraph &MN)
{
int i,j,k;
float w;
cout <<"输入顶点数和边数:";
cin >>MN.n>>MN.e;//输入图的顶点数和边数
cout << "输入顶点:";
for(i=1;i<=MN.n;i++)
cin>>MN.vex[i];//构造顶点向量
for(i=1;i<=MN.n;i++)
for(j=1;j<=MN.n;j++)
MN.arcs[i][j]=MAXVAL;//初始化邻接矩阵
for(k=1;k<=MN.e;k++)
{
cout<<"输入一条边依附的顶点的序号及权值:";
cin>>i>>j>>w;//输入一条边依附的顶点的序号及权值
MN.arcs[i][j]=w;//权值赋予邻接矩阵相应元素
}
}
void CreatDN_ALN(ALGraph &ALN)
{
node *p;
int i,j,k;
char ch;
cout << "输入顶点数:";
cin >> ALN.n;
cout <<"输入顶点信息:";
for(i=1;i<=ALN.n;i++)
{
cin >> ch;//读入顶点信息
ALN.adjlist[i].vexdata = ch;//设置顶点为字符型
ALN.adjlist[i].firstarc =NULL;//将链表初始化为空
}
cout << "读入一条边依附的顶点序号及权值:";
cin >> i >> j >> k;
while((i>0)&&(j>0))//输入(i,j)为(0,0)作结束标记
{
p = new node;//生成邻接点序号为j的表结点
p->info = k;
p->adjvex = j;
p->link = ALN.adjlist[i].firstarc;
ALN.adjlist[i].firstarc = p;//结点j插入到第i个链表
cout << "读入一条边依附的顶点序号及权值:";
cin >> i >> j >> k;
}
}
bool TopoOrder(ALGraph ALN,stack <int>&T,int ve[])//求ve并将逆序存入T
{
int i,m,k;
stack <int> S;
int degree[M];
for(i=1;i<=ALN.n;i++)
{
degree[i] = 0;//入度初始化为0
ve[i]=0;
}
InDegree(ALN,degree);
for(i=1;i<=ALN.n;i++)
if(degree[i] == 0)
S.push(i);
int count=0;//对输出顶点计数
while(!S.empty())
{
m=S.top();
T.push(m);//将入度为0的顶点入栈
S.pop();
++count;//计数
for(node *p = ALN.adjlist[m].firstarc;p != NULL; p=p->link)
{
k = p->adjvex;//对k号顶点的每个邻接点入度减1
if((--degree[k]) == 0)//若入度减为0,则入栈
S.push(k);
if((ve[m]+ p->info) > ve[k])
ve[k]=ve[m]+p->info;
}
}
if(count < ALN.n)
return false;
else
return true;
}
void Criticla_Path(ALGraph ALN)
{
int ve[M],vl[M];
int j,k,ee,el;
node *p;
stack <int> S;
if(!TopoOrder(ALN,S,ve))
cout << "存在回路";
else
{
for(int i =1;i<=ALN.n;i++)
vl[i]=ve[ALN.n];
while(!S.empty())//逆序求vl
{
for(j=S.top(),S.pop(),p=ALN.adjlist[j].firstarc;p!=NULL;p=p->link)
{
k=p->adjvex;
if(vl[k]-p->info < vl[j])
vl[j] =vl[k]-p->info;
}
}
cout << "关键路径为:";
for(j = 1;j<=ALN.n;++j)
for(p=ALN.adjlist[j].firstarc;p!=NULL;p=p->link)
{
k=p->adjvex;
ee=ve[j];//起始点最早发生时间
el=vl[k]-p->info;//活动最晚发生时间减去活动权值
if(ee==el)//ee与el相等则为关键路径
cout <<"<"<<j << ',' << k<<">"<< ' ';
}
}
}
void Shortest_Path(MGraph MN)
{
int i;//源点
cout << "输入源点:";
cin >> i;
int pre[M];
float dist[M];
int j,k,p,v;
int min;
for(j=1;j<=MN.n;j++)
{
dist[j]=MN.arcs[i][j];
if(dist[j]<MAXVAL)
pre[j]=i;
else
pre[j]=0;
MN.arcs[j][j]=0;
}
dist[i]=0;pre[i]=0;
MN.arcs[i][i]=1;//源点设置为被选出
for(k=1;k<=MN.n;k++)
{
min=MAXVAL;
j=-1;
for(p=1;p<=MN.n;p++)//选出最短路径的点
if((MN.arcs[p][p]==0)&&dist[p]<min)
{
j=p;
min=dist[p];
}
if(j==-1)
break;
else
{
MN.arcs[j][j]=1;
for(v=1;v<=MN.n;v++)//更新路径为下次作选择准备
if((MN.arcs[v][v]==0)&&((min+MN.arcs[j][v]) < dist[v]))
{
dist[v]=min+MN.arcs[j][v];
pre[v]=j;
}
}
}
cout << "选择终点:";
cin >> i;
cout << "最短路径为";
while(pre[i] != 0)
{
i=pre[i];
cout << i <<' ';
}
}
///