概述
//*******************************************引入头文件*********************************************
#include <stdio.h>
//使用了标准库函数
#include <stdlib.h>
//使用了动态内存分配函数
#include "SqQueue.cpp" //由于广度优先遍历要使用队列,而图中的顶点插入删除少访问多,故引入一个已写好的顺序队列
//******************************************自定义符号常量*******************************************
#define OVERFLOW -2
//内存溢出错误常量
#define ILLEGAL -1
//非法操作错误常量
#define OK 1
//表示操作正确的常量
#define ERROR 0
//表示操作错误的常量
//******************************************自定义数据类型********************************************
typedef int Status;
//用typedef给int起个别名,也便于程序的维护
typedef float ElemType;
//用typedef给float起个别名,也便于程序的维护
//-------------图的数组(邻接矩阵)存储表示
#define INFINITY
65535
//最大值 ∞
#define MAX_VERTEX_NUM
20
//最大顶点个数
typedef enum {DG,DN,UDG,UDN} GraphKind;
//(有向图,有向网,无向图,无向网)
typedef int VRType;
typedef int VertexType;
typedef struct ArcCell{
VRType
adj;
//VRType是顶点关系类型。对无权图,用1或0,表示相邻与否,对带权图,则为权值类型
}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct{
VertexType vexs[MAX_VERTEX_NUM];
//顶点向量
AdjMatrix
arcs;
//邻接矩阵
int vexnum,arcnum;
//图当前的定点数和弧数
GraphKind
kind;
//图的种类标志
}MGraph;
//*********************************************图的主要操作********************************************
//------------------------------------1.图的创建(构造) ----------------------------------------------
int LocateVex(MGraph G, int v){
//顶点定位函数
for(int i=0; i<=G.vexnum; ++i)
if(G.vexs[i]==v)
return i;
//若找到结点返回i
return -1;
//否则返回-1,表示没有找到
}//LocateVex
/*说明:图变网,加权值,改距离
有向变无向 ,置邻接矩阵
反之也对
加权值
0,1变 ∞
有向图 <------------------------------> 有向网
|
去权值
∞变 0,1
|
|
|
去对称矩阵
|
置对称矩阵
去对称矩阵
|
置对称矩阵
|
|
|
加权值
0,1变 ∞
|
无向图 <------------------------------> 无向网
去权值
∞变 0,1
*/
Status CreateUDN(MGraph &G){
//采用数组(邻接矩阵)表示法,构造无向网G
VertexType v1,v2;
int w,i,j;
printf("请依次输入无向网G的顶点数,弧数,用逗号隔开n");
scanf("%d,%d",&G.vexnum,&G.arcnum);
printf("请依次输入无向网G的顶点名称,用空格隔开n");
for(int i=0;i<G.vexnum;++i)
scanf("%d",&G.vexs[i]);
//构造各顶点向量
for(int i=0;i<G.vexnum;++i)
for(int j=0;j<G.vexnum;++j)
G.arcs[i][j].adj=INFINITY;
printf("请依次输入无向网G每条弧依附的两顶点名称及权值,输完一组按回车n");
for(int k=0;k<G.arcnum;++k){ //构造邻接矩阵
scanf("%d",&v1);
scanf("%d",&v2);
scanf("%d",&w);
i=LocateVex(G,v1);
j=LocateVex(G,v2);
//确定v1,v2在G中的位置
G.arcs[i][j].adj=w;
G.arcs[j][i]=G.arcs[i][j];
//置<v1,v2>的对称弧<v2,v1>
}//for
return OK;
}// CreateUDN
Status CreateUDG(MGraph &G){
//采用数组(邻接矩阵)表示法,构造无向图G
VertexType v1,v2;
int i,j;
printf("请依次输入无向图G的顶点数,弧数,用逗号隔开n");
scanf("%d,%d",&G.vexnum,&G.arcnum);
printf("请依次输入无向图G的顶点名称,用空格隔开n");
for(int i=0;i<G.vexnum;++i)
scanf("%d",&G.vexs[i]);
//构造各顶点向量
for(int i=0;i<G.vexnum;++i)
for(int j=0;j<G.vexnum;++j)
//预置邻接矩阵
G.arcs[i][j].adj=0;
printf("请依次输入无向图G每条弧依附的两顶点名称,输完一组按回车n");
for(int k=0;k<G.arcnum;++k){ //构造邻接矩阵
scanf("%d",&v1);
scanf("%d",&v2);
i=LocateVex(G,v1);
j=LocateVex(G,v2);
//确定v1,v2在G中的位置
G.arcs[i][j].adj=1;
G.arcs[j][i]=G.arcs[i][j];
//置<v1,v2>的对称弧<v2,v1>
}//for
return OK;
}// CreateUDG
Status CreateDN(MGraph &G){
//采用数组(邻接矩阵)表示法,构造有向网G
VertexType v1,v2;
int w,i,j;
printf("请依次输入有向网G的顶点数,弧数,用逗号隔开n");
scanf("%d,%d",&G.vexnum,&G.arcnum);
printf("请依次输入有向网G的顶点名称,用空格隔开n");
for(int i=0;i<G.vexnum;++i)
scanf("%d",&G.vexs[i]);
//构造各顶点向量
for(int i=0;i<G.vexnum;++i)
for(int j=0;j<G.vexnum;++j)
G.arcs[i][j].adj=INFINITY;
printf("请依次输入有向网G每条弧依附的两顶点名称及权值,输完一组按回车n");
for(int k=0;k<G.arcnum;++k){ //构造邻接矩阵
scanf("%d",&v1);
scanf("%d",&v2);
scanf("%d",&w);
i=LocateVex(G,v1);
j=LocateVex(G,v2);
//确定v1,v2在G中的位置
G.arcs[i][j].adj=w;
}//for
return OK;
}// CreateDN
Status CreateDG(MGraph &G){
//采用数组(邻接矩阵)表示法,构造有向图G
VertexType v1,v2;
int i,j;
printf("请依次输入有向图G的顶点数,弧数,用逗号隔开n");
scanf("%d,%d",&G.vexnum,&G.arcnum);
printf("请依次输入有向图G的顶点名称,用空格隔开n");
for(int i=0;i<G.vexnum;++i)
scanf("%d",&G.vexs[i]);
//构造各顶点向量
for(int i=0;i<G.vexnum;++i)
for(int j=0;j<G.vexnum;++j)
G.arcs[i][j].adj=0;
printf("请依次输入有向图G每条弧依附的两顶点名称,输完一组按回车n");
for(int k=0;k<G.arcnum;++k){ //构造邻接矩阵
scanf("%d",&v1);
scanf("%d",&v2);
i=LocateVex(G,v1);
j=LocateVex(G,v2);
//确定v1,v2在G中的位置
G.arcs[i][j].adj=1;
}//for
return OK;
}// CreateDG
Status CreateGraph(MGraph &G){
//总函数
//采用数组(邻接矩阵)表示法,构造图G
printf("请输入您想构造的图的类型:有向图,有向网,无向图,无向网,分别对应0,1,2,3):");
int temp;
scanf("%d",&temp);
//输入所要构造图的类型
G.kind=(GraphKind)temp;
switch((GraphKind)temp){
case
DG:
return CreateDG(G);
//构造有向图G
case
DN:
return CreateDN(G);
//构造有向网G
case UDG:
return CreateUDG(G); //构造无向图G
case UDN:
return CreateUDN(G); //构造无向网G
default :
return ERROR;
}
}//CreateGraph
//---------------------------------2.邻接矩阵的输出 ----------------------------------------------
Status PrintAdjMatrix(MGraph G){
//打印某个图的邻接矩阵
//采用数组(邻接矩阵)表示法,构造图G
for(int i=0;i<G.vexnum;i++){
for(int j=0;j<G.vexnum;j++)
if(G.arcs[i][j].adj==INFINITY)
printf("
∞ ");
else
printf(" %3d ", G.arcs[i][j].adj);
printf("nn");
}
}//PrintAdjMatrix
//------------------------------------3.图的遍历 ----------------------------------------------
int FirstAdjVex(MGraph G,VertexType v){
//求顶点v在图G中的第一个邻接点
int i,j=0,k;
k=LocateVex(G,v);
//v是顶点,不是序号!需要定位
if(G.kind==DN||G.kind==UDN)
//若是网
j=INFINITY;
for(i=0;i<G.vexnum;++i)
if(G.arcs[k][i].adj!=j)
return i;
//若找到则返回i
return -1;
//若未找到返回-1
}//FirstAdjVex
int NextAdjVex(MGraph G,VertexType v,VertexType w){
//求顶点v在图G中相对于邻接点w的下一个邻接点
int i,j=0,k1,k2;
k1=LocateVex(G,v);
//v是顶点,不是序号!需要定位
k2=LocateVex(G,w);
//w是顶点,不是序号!需要定位
if(G.kind==DN||G.kind==UDN)
//若是网
j=INFINITY;
for(i=k2+1;i<G.vexnum;++i)
if(G.arcs[k1][i].adj!=j)
return i;
//若找到则返回i
return -1;
//若未找到返回-1
}//NextAdjVex
//-----------------------深度优先遍历DFS-----------------------------
typedef enum { TRUE=1 , FALSE=0 } Boolean;
Boolean visited[MAX_VERTEX_NUM];
//访问标志数组
Status (*VisitFunc)(int v);
//函数变量
Status Print(int v){
//元素访问函数
printf(" %3d ",v);
return OK;
}//Print
void DFSTraverse(MGraph G,Status (*Visit)(int v)){
//对图G作深度优先遍历,调用Visit()函数访问结点
void DFS(MGraph G,int v);
//函数声明
VisitFunc=Visit;
//使用全局变量VisitFunc,使DFS不必设函数指针参数
for(int v=0;v<G.vexnum;++v)
visited[v]=FALSE;
//预置标志数组
for(int v=0;v<G.vexnum;++v)
if(!visited[v])
//若该顶点未被访问
DFS(G,v);
}//DFSTraverse
void DFS(MGraph G,int v){
//从第v个顶点出发递归地深度优先遍历图G
visited[v]=TRUE;
//先将访问标志数组该元素的访问标志改为True
//注意,序号v从0开始,所以序号v总比第v个顶点在图中的位置少1
VisitFunc(G.vexs[v]);
//访问第v个顶点
注意:v是序号,不是顶点!
for(int w=FirstAdjVex(G,G.vexs[v]);w>=0;w=NextAdjVex(G,G.vexs[v],G.vexs[w])){
//v是序号,不是顶点!
if(!visited[w])
DFS(G,w);
//对v的尚未访问的邻接点w递归调用DFS
}//for
}//DFS
//----------------广度优先遍历 (需要使用队列)BFS------------
//说明:队列的相关代码包含在"SqQueue.cpp"中,关于队列的详细方法请阅读该文件
void BFSTraverse(MGraph G,Status (*Visit)(int v)){
//按广度优先非递归遍历图G,使用辅助队列Q和访问标志数组visited
SqQueue Q;
for(int v=0;v<G.vexnum;++v)
visited[v]=FALSE;
//预置标志数组
InitQueue_Sq(Q);
//置空辅助队列Q
for(int v=0;v<G.vexnum;++v)
if(!visited[v]){
//v尚未访问
visited[v]=TRUE;
Visit(G.vexs[v]);
//访问第v顶点
EnQueue_Sq(Q,v);
//v入队列
while(!QueueEmpty_Sq(Q)){
//队列不空
DeQueue_Sq(Q,v);
//队头元素出队并置为u
for(int w=FirstAdjVex(G,G.vexs[v]);w>=0;w=NextAdjVex(G,G.vexs[v],G.vexs[w])){
if(!visited[w]){
//w为v尚未访问的邻接顶点
visited[w]=TRUE;
Visit(G.vexs[w]);
//访问第w顶点
}//if
}//for
}//while
}//if
}//BFSTraverse
//------------------------------------ 4.最小生成树 ----------------------------------------------
//-------------------辅助数组的定义-------------------------------
struct Record{
VertexType adjvex;
//顶点
VRType
lowcost;
//最低代价
}closedge[MAX_VERTEX_NUM];
int minimum(Record closedge[]){
int reserve=65535,min;
for(int i=1;i<MAX_VERTEX_NUM;i++)
if(closedge[i].lowcost<reserve&&closedge[i].lowcost>0){
//没有访问过但是存在路径
reserve=closedge[i].lowcost;
min=i;
}//if
return min;
}//minimum
void MiniSpanTree_PRIM(MGraph G,VertexType u){
//普里姆算法求最小生成树
//用普里姆算法从第u个顶点出发构造网G的最小生成树T,输出T的各条边
//记录从定点集U到V-U的代价最小的边的辅助数组定义
int k=LocateVex(G,u);
for(int j=0;j<G.vexnum;++j)
//辅助数组初始化
if(j!=k){
closedge[j].adjvex=u;
closedge[j].lowcost=G.arcs[k][j].adj;
//{adjvex, lowcost}
}//if
closedge[k].lowcost=0;
//初始,U={u}
printf("最小生成树各条边:n顶点
权值
顶点
n");
for(int i=1;i<G.vexnum;++i){
k=minimum(closedge);
//求出T的下一个结点:第k顶点
//此时closedge[k].lowcost= MIN{ closedge[vi].lowcost | closedge[vi].lowcost>0, vi ∈V-U}
printf(" %2d <--- %2d ---> %2d n",closedge[k].adjvex,closedge[k].lowcost,G.vexs[k]);
//输出生成树的边及其权值
closedge[k].lowcost = 0;
//第k顶点并入U集
for(int j=1;j<G.vexnum;++j)
if(G.arcs[k][j].adj < closedge[j].lowcost){
//新顶点并入U后重新选择最小边(更新最小边信息)
closedge[j].adjvex=G.vexs[k];
closedge[j].lowcost=G.arcs[k][j].adj;
}//if
}//for
}//MiniSpanTree_PRIM
//------------------------------------ 5.最短路径 ----------------------------------------------
//---------------------------迪斯特拉算法辅助数组的定义--------------------------------
typedef int PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef int ShortPathTable[MAX_VERTEX_NUM];
void ShortestPath_DIJ(MGraph G,int v0,PathMatrix &P,ShortPathTable &D){
//用迪斯特拉算法求有向图G最短路径
//用Dijkstra算法求有向图G的顶点v0顶点到其余顶点v的最短路径P[v]及其带权长度D[v]
//若P[v][w]为TRUE,则w是从v0到v当前求得最小路径上的顶点
//final[v]为TRUE当且仅当v∈S,即已经求得v0到v的最短路径
int i,v,w,j,min;
Status final[MAX_VERTEX_NUM];
for(v=0;v<G.vexnum;++v){
final[v]=FALSE;
D[v]=G.arcs[v0][v].adj;
for(w=0;w<G.vexnum;++w)
P[v][w]=FALSE;
//设空路径
if(D[v]<INFINITY){
P[v][v0]=TRUE;
P[v][w]=TRUE;
}//if
}//for
D[v0]=0;
final[v0]=TRUE;
//初始化,v0顶点属于S集
//开始主循环,每次求得v0到某个顶点v的最短路径,并加v到S集
for(i=0;i<G.vexnum;++i){
//其余G.vexnum-1个顶点
min=INFINITY;
//当前所知离v0顶点最近距离
for(w=0;w<G.vexnum;++w)
if(!final[w])
//w顶点在V-S中
if(D[w]<min){
v=w;
//w顶点离v0顶点更近
min=D[w];
}//if
final[v]=TRUE;
//离v0顶点最近的v加入S集
for(w=0;w<G.vexnum;++w)
//更新当前最短路径及距离
if(!final[w]&&(min+G.arcs[v][w].adj<D[w])){
//修改D[w]和P[w],w∈V-S
D[w]=min+G.arcs[v][w].adj;
for(j=0;j<G.vexnum;++j)
P[w][j]=P[v][j];
P[w][w]=TRUE;
//P[w]=P[v]+[w]
}//if
}//for
}//ShortestPath_DIJ
//---------------------------弗洛伊德算法辅助数组的定义--------------------------------
typedef int PathMatrix1[MAX_VERTEX_NUM][MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef int DistanceMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
void ShortestPath_FLOYD(MGraph G,PathMatrix1 &P,DistanceMatrix &D){
//用弗洛伊德算法求有向网G最短路径
//用Floyd算法求有向网G中各对顶点v和w之间的最短路径P[v][w]及其带权长度D[v][w]。
//若P[v][w][u]为TRUE,则u是从v到w当前求得最短路径上的顶点。
int v,w,u,i;
for(v=0;v<G.vexnum;++v)
//各对结点之间的初始已知路径及距离
for(w=0;w<G.vexnum;++w){
D[v][w]=G.arcs[v][w].adj;
for(u=0;u<G.vexnum;++u)
P[v][w][u]=FALSE;
if(D[v][w]<INFINITY){
//从v到w有直接路径
P[v][w][v]=TRUE;
P[v][w][w]=TRUE;
}//if
}//for
for(u=0;u<G.vexnum;++u)
for(v=0;v<G.vexnum;++v)
for(w=0;w<G.vexnum;++w)
if(D[v][u]+D[u][v]<D[v][w]){
//从v经u到w的一条路径更短
D[v][w]=D[v][u]+D[u][w];
for(i=0;i<G.vexnum;++i)
P[v][w][i]=P[v][u][i]||P[u][w][i];
}//if
}//ShortestPath_FLOYD
//-------------------------------主函数-------------------------------
int main(int argc,char *argv[]){
printf("n---------------------------------图的邻接矩阵表示-------------------------------n");
MGraph G;
printf("
----------------------图的建立------------------
n");
CreateGraph(G);
//图的创建
printf("
--------------------图的邻接矩阵----------------
nn");
PrintAdjMatrix(G);
//打印邻接矩阵
printf("
----------------------图的遍历------------------
n");
printf("深度优先遍历结果:");
DFSTraverse(G,Print);
printf("n广度优先遍历结果:");
BFSTraverse(G,Print);
printf("n");
if(G.kind==UDN){
//若为无向网,求其最小生成树
printf("
-----------------无向网的最小生成树-------------
n");
MiniSpanTree_PRIM(G,G.vexs[0]);
}//if
int v0=0;
//源点
PathMatrix P;
PathMatrix1 P1;
ShortPathTable D;
DistanceMatrix D1;
if(G.kind==DN){
printf("
------------------有向网的最短路径--------------
n");
printf("ttt执行迪斯特拉算法:n");
ShortestPath_DIJ(G,v0,P,D);
printf("最短路径数组P[i][j]如下:n");
for(int i=0;i<G.vexnum;++i){
for(int j=0;j<G.vexnum;++j)
printf(" %3d ",P[i][j]);
printf("n");
}//for
printf("顶点%d到其他顶点的最短路径如下:n",v0);
for(int i=0;i<G.vexnum;++i)
printf("%d--->%d :%3dn",v0,G.vexs[i],D[i]);
printf("ttt执行弗洛伊德算法:n");
for(int i=0;i<G.vexnum;++i)
G.arcs[i][i].adj=0;
//ShortestPath_FLOYD()要求对角线元素为0
printf("执行算法前的邻接矩阵如下:n");
PrintAdjMatrix(G);
ShortestPath_FLOYD(G,P1,D1);
printf("DistanceMatrix矩阵:n");
for(int i=0;i<G.vexnum;++i){
for(int j=0;j<G.vexnum;++j){
if(D1[i][j])
printf("
∞ ");
else
printf(" %5d ",D1[i][j]);
}//for
printf("nn");
}//for
printf("n最短路径的计算结果:n");
for(int i=0;i<G.vexnum;++i)
for(int j=0;j<G.vexnum;++j)
printf("%d--->%d 最短路径:%dn",G.vexs[i],G.vexs[j],D1[i][j]);
printf("n最短路径数组P[i][j][k]如下:n");
for(int i=0;i<G.vexnum;++i)
for(int j=0;j<G.vexnum;++j)
for(int k=0;k<G.vexnum;++k){
printf("P[%d][%d][%d]=%d
",i,j,k,P1[i][j][k]);
if((k+1)%3==0)
printf("n");
}//for
}//if
return 0;
}
/*--------------------------输入全程记录(便于测试,可直接复制)------------------------------
说明:下面输入的无向图来自教材P174页,可以直接去该页寻找最小生成树正确结果,以便于验证算法正确与否
---------------------------------图的邻接矩阵表示-------------------------------
----------------------图的建立------------------
请输入您想构造的图的类型:有向图,有向网,无向图,无向网,分别对应0,1,2,3):3
请依次输入无向网G的顶点数,弧数,用逗号隔开
6,10
请依次输入无向网G的顶点名称,用空格隔开
1 2 3 4 5 6
请依次输入无向网G每条弧依附的两顶点名称及权值,输完一组按回车
1 2 6
1 4 5
1 3 1
3 2 5
3 4 5
3 5 6
3 6 4
2 5 3
4 6 2
5 6 6
--------------------图的邻接矩阵----------------
∞
6
1
5
∞
∞
6
∞
5
∞
3
∞
1
5
∞
5
6
4
5
∞
5
∞
∞
2
∞
3
6
∞
∞
6
∞
∞
4
2
6
∞
----------------------图的遍历------------------
深度优先遍历结果:
1
2
3
4
6
5
广度优先遍历结果:
1
2
3
4
5
6
-----------------无向网的最小生成树-------------
最小生成树各条边:
顶点
权值
顶点
1 <---
1 --->
3
3 <---
4 --->
6
6 <---
2 --->
4
3 <---
5 --->
2
2 <---
3 --->
5
--------------------------------
Process exited with return value 0
Press any key to continue . . .
说明:下面输入的无向图来自教材P188页,可以直接去该页寻找最短路径的正确结果,以便于验证算法正确与否
---------------------------------图的邻接矩阵表示-------------------------------
----------------------图的建立------------------
请输入您想构造的图的类型:有向图,有向网,无向图,无向网,分别对应0,1,2,3):1
请依次输入有向网G的顶点数,弧数,用逗号隔开
6,8
请依次输入有向网G的顶点名称,用空格隔开
0 1 2 3 4 5
请依次输入有向网G每条弧依附的两顶点名称及权值,输完一组按回车
0 5 100
0 4 30
0 2 10
1 2 5
2 3 50
4 3 20
4 5 60
3 5 10
--------------------图的邻接矩阵----------------
∞
∞
10
∞
30
100
∞
∞
5
∞
∞
∞
∞
∞
∞
50
∞
∞
∞
∞
∞
∞
∞
10
∞
∞
∞
20
∞
60
∞
∞
∞
∞
∞
∞
----------------------图的遍历------------------
深度优先遍历结果:
0
2
3
5
4
1
广度优先遍历结果:
0
2
4
5
1
3
------------------有向网的最短路径--------------
执行迪斯特拉算法:
最短路径数组P[i][j]如下:
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
0
1
0
0
1
0
0
1
0
0
0
0
0
1
0
0
1
0
1
顶点0到其他顶点的最短路径如下:
0--->0 :
0
0--->1 :65535
0--->2 : 10
0--->3 : 50
0--->4 : 30
0--->5 : 60
执行弗洛伊德算法:
执行算法前的邻接矩阵如下:
0
∞
10
∞
30
100
∞
0
5
∞
∞
∞
∞
∞
0
50
∞
∞
∞
∞
∞
0
∞
10
∞
∞
∞
20
0
60
∞
∞
∞
∞
∞
0
DistanceMatrix矩阵:
0
∞
∞
∞
∞
∞
∞
0
∞
∞
∞
∞
∞
∞
0
∞
∞
∞
∞
∞
∞
0
∞
∞
∞
∞
∞
∞
0
∞
∞
∞
∞
∞
∞
0
最短路径的计算结果:
0--->0 最短路径:0
0--->1 最短路径:65535
0--->2 最短路径:10
0--->3 最短路径:65535
0--->4 最短路径:30
0--->5 最短路径:100
1--->0 最短路径:65535
1--->1 最短路径:0
1--->2 最短路径:5
1--->3 最短路径:65535
1--->4 最短路径:65535
1--->5 最短路径:65535
2--->0 最短路径:65535
2--->1 最短路径:65535
2--->2 最短路径:0
2--->3 最短路径:50
2--->4 最短路径:65535
2--->5 最短路径:65535
3--->0 最短路径:65535
3--->1 最短路径:65535
3--->2 最短路径:65535
3--->3 最短路径:0
3--->4 最短路径:65535
3--->5 最短路径:10
4--->0 最短路径:65535
4--->1 最短路径:65535
4--->2 最短路径:65535
4--->3 最短路径:20
4--->4 最短路径:0
4--->5 最短路径:60
5--->0 最短路径:65535
5--->1 最短路径:65535
5--->2 最短路径:65535
5--->3 最短路径:65535
5--->4 最短路径:65535
5--->5 最短路径:0
最短路径数组P[i][j][k]如下:
P[0][0][0]=1
P[0][0][1]=0
P[0][0][2]=0
P[0][0][3]=0
P[0][0][4]=0
P[0][0][5]=0
P[0][1][0]=1
P[0][1][1]=0
P[0][1][2]=0
P[0][1][3]=0
P[0][1][4]=0
P[0][1][5]=0
P[0][2][0]=1
P[0][2][1]=0
P[0][2][2]=1
P[0][2][3]=0
P[0][2][4]=0
P[0][2][5]=0
P[0][3][0]=1
P[0][3][1]=0
P[0][3][2]=0
P[0][3][3]=0
P[0][3][4]=0
P[0][3][5]=0
P[0][4][0]=1
P[0][4][1]=0
P[0][4][2]=0
P[0][4][3]=0
P[0][4][4]=1
P[0][4][5]=0
P[0][5][0]=1
P[0][5][1]=0
P[0][5][2]=0
P[0][5][3]=0
P[0][5][4]=0
P[0][5][5]=1
P[1][0][0]=0
P[1][0][1]=1
P[1][0][2]=0
P[1][0][3]=0
P[1][0][4]=0
P[1][0][5]=0
P[1][1][0]=0
P[1][1][1]=1
P[1][1][2]=0
P[1][1][3]=0
P[1][1][4]=0
P[1][1][5]=0
P[1][2][0]=0
P[1][2][1]=1
P[1][2][2]=1
P[1][2][3]=0
P[1][2][4]=0
P[1][2][5]=0
P[1][3][0]=0
P[1][3][1]=1
P[1][3][2]=0
P[1][3][3]=0
P[1][3][4]=0
P[1][3][5]=0
P[1][4][0]=0
P[1][4][1]=1
P[1][4][2]=0
P[1][4][3]=0
P[1][4][4]=0
P[1][4][5]=0
P[1][5][0]=0
P[1][5][1]=1
P[1][5][2]=0
P[1][5][3]=0
P[1][5][4]=0
P[1][5][5]=0
P[2][0][0]=0
P[2][0][1]=0
P[2][0][2]=1
P[2][0][3]=0
P[2][0][4]=0
P[2][0][5]=0
P[2][1][0]=0
P[2][1][1]=0
P[2][1][2]=1
P[2][1][3]=0
P[2][1][4]=0
P[2][1][5]=0
P[2][2][0]=0
P[2][2][1]=0
P[2][2][2]=1
P[2][2][3]=0
P[2][2][4]=0
P[2][2][5]=0
P[2][3][0]=0
P[2][3][1]=0
P[2][3][2]=1
P[2][3][3]=1
P[2][3][4]=0
P[2][3][5]=0
P[2][4][0]=0
P[2][4][1]=0
P[2][4][2]=1
P[2][4][3]=0
P[2][4][4]=0
P[2][4][5]=0
P[2][5][0]=0
P[2][5][1]=0
P[2][5][2]=1
P[2][5][3]=0
P[2][5][4]=0
P[2][5][5]=0
P[3][0][0]=0
P[3][0][1]=0
P[3][0][2]=0
P[3][0][3]=1
P[3][0][4]=0
P[3][0][5]=0
P[3][1][0]=0
P[3][1][1]=0
P[3][1][2]=0
P[3][1][3]=1
P[3][1][4]=0
P[3][1][5]=0
P[3][2][0]=0
P[3][2][1]=0
P[3][2][2]=0
P[3][2][3]=1
P[3][2][4]=0
P[3][2][5]=0
P[3][3][0]=0
P[3][3][1]=0
P[3][3][2]=0
P[3][3][3]=1
P[3][3][4]=0
P[3][3][5]=0
P[3][4][0]=0
P[3][4][1]=0
P[3][4][2]=0
P[3][4][3]=1
P[3][4][4]=0
P[3][4][5]=0
P[3][5][0]=0
P[3][5][1]=0
P[3][5][2]=0
P[3][5][3]=1
P[3][5][4]=0
P[3][5][5]=1
P[4][0][0]=0
P[4][0][1]=0
P[4][0][2]=0
P[4][0][3]=0
P[4][0][4]=1
P[4][0][5]=0
P[4][1][0]=0
P[4][1][1]=0
P[4][1][2]=0
P[4][1][3]=0
P[4][1][4]=1
P[4][1][5]=0
P[4][2][0]=0
P[4][2][1]=0
P[4][2][2]=0
P[4][2][3]=0
P[4][2][4]=1
P[4][2][5]=0
P[4][3][0]=0
P[4][3][1]=0
P[4][3][2]=0
P[4][3][3]=1
P[4][3][4]=1
P[4][3][5]=0
P[4][4][0]=0
P[4][4][1]=0
P[4][4][2]=0
P[4][4][3]=0
P[4][4][4]=1
P[4][4][5]=0
P[4][5][0]=0
P[4][5][1]=0
P[4][5][2]=0
P[4][5][3]=0
P[4][5][4]=1
P[4][5][5]=1
P[5][0][0]=0
P[5][0][1]=0
P[5][0][2]=0
P[5][0][3]=0
P[5][0][4]=0
P[5][0][5]=1
P[5][1][0]=0
P[5][1][1]=0
P[5][1][2]=0
P[5][1][3]=0
P[5][1][4]=0
P[5][1][5]=1
P[5][2][0]=0
P[5][2][1]=0
P[5][2][2]=0
P[5][2][3]=0
P[5][2][4]=0
P[5][2][5]=1
P[5][3][0]=0
P[5][3][1]=0
P[5][3][2]=0
P[5][3][3]=0
P[5][3][4]=0
P[5][3][5]=1
P[5][4][0]=0
P[5][4][1]=0
P[5][4][2]=0
P[5][4][3]=0
P[5][4][4]=0
P[5][4][5]=1
P[5][5][0]=0
P[5][5][1]=0
P[5][5][2]=0
P[5][5][3]=0
P[5][5][4]=0
P[5][5][5]=1
--------------------------------
Process exited with return value 0
Press any key to continue . . .
*/
2.0
#include <stdio.h>
#include <stdlib.h>
#define MAX_VEX_NUM 20
#define INFINITY -1
// 顶点访问标志类型声明
typedef enum {UNVISITED=0, VISITED=1} visit_t;
// 采用邻接矩阵表示法的图类型定义
// 这里假设:顶点的信息为 unsigned int类型;边的信息 也为 unsigned int类型, 1表示有边, 0 表示无边。
typedef struct
{
unsigned int vertex[MAX_VEX_NUM];
unsigned int arcs[MAX_VEX_NUM][MAX_VEX_NUM];
int vex_num, arc_num;
} m_graph_t;
// 输出图的邻接矩阵
void print_graph(m_graph_t g)
{
int i, j;
for (i=0; i<g.vex_num; i++) {
for (j=0; j<g.vex_num; j++)
printf("%3d", g.arcs[i][j]);
printf("n");
}
}
// 求图g中顶点v的第一个邻接点,若存在,则返回该邻接点在图中的位置(>=0);否则返回-1。
int first_adj(m_graph_t g, int v)
{
int w = 0;
while ((w<g.vex_num) && (g.arcs[v][w]==0)) w++;
if (w==g.vex_num) return -1;
else return w;
}
// 求图g中顶点v的相对于邻接点w的下一个邻接点,若存在,则返回该邻接点在图中的位置(>=0);否则返回-1。
int next_adj(m_graph_t g, int v, int w)
{
int u = w+1;
while ((u<g.vex_num) && (g.arcs[v][u]==0)) u++;
if (u==g.vex_num) return -1;
else return u;
}
// 深度优先搜索遍历
visit_t visited[MAX_VEX_NUM];
void depth_first(m_graph_t g, int v)
{
int w;
visited[v] = VISITED;
printf("%3d",g.vertex[v]);
for (w=first_adj(g, v); w >= 0; w=next_adj(g, v, w))
if (!visited[w]) depth_first(g, w);
}
void depth_first_traverse(m_graph_t g)
{
int v;
for (v=0;v<g.vex_num;v++) visited[v] = UNVISITED;
for (v=0;v<g.vex_num;v++)
if (!visited[v]) depth_first(g, v);
}
// 队列的存储结构及基本操作
typedef unsigned int queue_elem_t;
// typedef int queue_elem_t;
typedef enum {EMPTY, FULL, READY} status_t;
typedef struct
{
queue_elem_t *data;
int front;
int rear;
int queue_len;
status_t status;
} queue;
typedef queue *queue_t;
queue_t init_queue(int len)
{
queue_t q = (queue_t)malloc(sizeof(queue));
if (!q) {
printf("Heap full.n");
exit(-1);
}
q->data = (queue_elem_t *)malloc(sizeof(queue_elem_t) * len);
if (!q->data) {
printf("Heap full.n");
exit(-1);
}
q->front = q->rear = 0;
q->queue_len = len;
q->status = EMPTY;
return q;
}
queue_t destroy_queue(queue_t q)
{
if (q) {
free(q->data);
free(q);
}
return NULL;
}
int is_empty(queue_t q)
{
return (q->status==EMPTY);
}
void enqueue(queue_t q, queue_elem_t data)
{
if (!q) {
printf("You need init queue before using it.n");
exit(-1);
}
if (q->status != FULL) {
q->data[q->rear] = data;
q->rear = (q->rear + 1) % q->queue_len;
if (q->rear == q->front)
q->status = FULL;
else
q->status = READY;
}
}
queue_elem_t dequeue(queue_t q)
{
queue_elem_t data;
if (!q) {
printf("You need init queue before using it.n");
exit(-1);
}
if (q->status != EMPTY) {
data = q->data[q->front];
q->front = (q->front + 1) % q->queue_len;
if (q->front == q->rear)
q->status = EMPTY;
else
q->status = READY;
}
return data;
}
queue_elem_t get_front(queue_t q)
{
return q->data[q->front];
}
void visit_front(queue_t q, void (*do_front)(queue_elem_t *))
{
if (q->status != EMPTY)
do_front(&(q->data[q->front]));
}
void traverse_queue(queue_t q, void (*do_data)(queue_elem_t *))
{
int front;
if (q->status != EMPTY) {
front = q->front;
do {
do_data(&(q->data[front]));
front = (front + 1) % q->queue_len;
} while (front != q->rear);
}
}
// 广度优先搜索遍历
void breadth_first_traverse(m_graph_t g)
{
visit_t visited[MAX_VEX_NUM];
int u, v, w;
queue_t q = init_queue(g.vex_num);
for (v=0;v<g.vex_num;v++) visited[v] = UNVISITED;
for (v=0;v<g.vex_num;v++)
if (!visited[v]) {
visited[v] = VISITED;
printf("%3d", g.vertex[v]);
enqueue(q, v);
while (!is_empty(q)) {
u = dequeue(q);
for (w=first_adj(g, u); w!=-1; w=next_adj(g, u, w))
if (!visited[w]) {
visited[w] = VISITED;
printf("%3d", g.vertex[w]);
enqueue(q, w);
} //if
} // while
} // if
destroy_queue(q);
}
// 顶点定位函数
int LocateVex(m_graph_t *g, unsigned int v){
int i;
for (i = 0; i <= g->vex_num; ++i){
if(g->vertex[i]==v) return i;
}
return -1;
}
// 无向图构造函数
void create_UDG(m_graph_t *g)
{ //采用数组(邻接矩阵)表示法,构造无向网g。
int i, j, k;
unsigned int v1, v2;
printf("请输入图的顶点数和边数:");
scanf("%d,%d", &g->vex_num, &g->arc_num);
printf("请输入%d个顶点的信息:n", g->vex_num);
for (i = 0; i < g->vex_num; ++i) scanf("%d", &g->vertex[i]); //构造顶点向量
for (i = 0; i < g->vex_num; ++i) //初始化邻接矩阵
for (j = 0; j < g->vex_num; ++j) g->arcs[i][j] = 0;
printf("请输入%d条边的信息:", g->arc_num);
for (k = 0; k < g->arc_num; ++k) { //构造邻接矩阵
printf("n第%d条边(输入该边所依附的两个顶点):", k+1);
scanf("%d,%d",&v1, &v2);
//输入一条边依附的顶点
i = LocateVex(g, v1); j = LocateVex(g, v2); //确定v1和v2在G中位置
g->arcs[i][j] = 1;
g->arcs[j][i] = g->arcs[i][j]; //置<v1, v2>的对称边<v2, v1>
}
return;
}
/*
1
/
/
2
3
/
/
4
5 6---7
/
8
*/
int main()
{
/*
m_graph_t g = {
{1, 2, 3, 4, 5, 6, 7, 8}, // vertex
{{
0,
1,
1,
0,
0,
0,
0,
0}, // arcs
{
1,
0,
0,
1,
1,
0,
0,
0},
{
1,
0,
0,
0,
0,
1,
1,
0},
{
0,
1,
0,
0,
0,
0,
0,
1},
{
0,
1,
0,
0,
0,
0,
0,
1},
{
0,
0,
1,
0,
0,
0,
1,
0},
{
0,
0,
1,
0,
0,
1,
0,
0},
{
0,
0,
0,
1,
1,
0,
0,
0}},
8, // vex_num
9 // arc_num
};
*/
m_graph_t g;
create_UDG(&g);
// 调用创建无向图的函数
print_graph(g); printf("n");
depth_first_traverse(g); printf("n");
breadth_first_traverse(g); printf("n");
return 0;
}
最后
以上就是动人小海豚为你收集整理的图的全部内容,希望文章能够帮你解决图所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复