数据结构之图的应用
/*图的邻接矩阵和邻接表的转换,图的遍历,最小生成树等*/
#include "stdio.h"
#include "malloc.h"
#define INF 32767 //表示正无穷
#define MAXV 100 //最大顶点个数
int visited[MAXV]; //全局数组
//定义邻接矩阵类型
typedef int InfoType;
typedef struct {
int NO; //顶点编号
InfoType info; //顶点的其他信息
}VertexType; //顶点类型
typedef struct {
int edges[MAXV][MAXV]; //邻接矩阵
int n,e; //顶点数、边数
VertexType Vexs[MAXV]; //存放顶点信息
}MGraph; //图的邻接矩阵类型
//定义邻接表类型
typedef struct ANode { //边的节点结构类型
int adjvex; //该边的终点位置
struct ANode *nextarc; //指向下一条边的指针
InfoType info; //该边的相关信息,这里用于存放权值
}ArcNode;
typedef int Vertex;
typedef struct VNode { //邻接表头节点的类型
Vertex data; //顶点信息
ArcNode *firstarc; //指向第一条边
}VNode;
typedef VNode Adjlist[MAXV];//Adjlist是邻接表类型
typedef struct {
Adjlist adjlist; //邻接表
int n,e; //图中顶点数n和边数e
}ALGraph; //图的邻接表类型
//不带权值的图
void MarToList(MGraph g,ALGraph *&G) //将邻接矩阵g转化为邻接表G
{
int i,j;
ArcNode *p;
G=(ALGraph *)malloc(sizeof(ALGraph));
for(i=0;i<g.n ;i++) //给邻接表中所有头节点的指针域赋初值
G->adjlist [i].firstarc =NULL;
for(i=0;i<g.n ;i++)
for(j=g.n -1;j>=0;j--)
if(g.edges [i][j]!=0) //邻接矩阵当前元素不为0
{
p=(ArcNode *)malloc(sizeof(ArcNode));//创建一个节点*p
p->adjvex =j;
p->nextarc =G->adjlist [i].firstarc ;//将*p链到链表后
G->adjlist [i].firstarc =p;
}
G->n =g.n ;
G->e =g.e ;
}
void LisrToMat(ALGraph *G,MGraph &g) //将邻接表G转换成邻接矩阵g
{
int i,j;
ArcNode *p;
for(i=0;i<G->n ;i++) //g.edges[i][j]赋初值0
for(j=0;j<G->n ;j++)
g.edges [i][j]=0;
for(i=0;i<G->n ;i++)
{
p=G->adjlist[i].firstarc ;
while(p!=NULL)
{
g.edges [i][p->adjvex ]=1;
p=p->nextarc ;
}
}
g.n =G->n ;
g.e =G->e ;
}
void DispMat(MGraph g) //输出邻接矩阵g
{
int i,j;
for(i=0;i<g.n ;i++)
{
for(j=0;j<g.n ;j++)
printf("%3d",g.edges [i][j]);
printf("\n");
}
}
void DispAdj(ALGraph *G)
{
int i;
ArcNode *p;
for(i=0;i<G->n ;i++)
{
p=G->adjlist [i].firstarc ;
printf("%3d:",i);
while(p!=NULL)
{
printf("%3d",p->adjvex ) ;
p=p->nextarc;
}
printf("\n");
}
}
//带权值的图
void MatToList1(MGraph g,ALGraph *&G)
{
int i,j;
ArcNode *p;
G=(ALGraph *)malloc(sizeof(ALGraph));
for(i=0;i<g.n ;i++)
G->adjlist[i].firstarc =NULL;
for(i=0;i<g.n ;i++)
for(j=g.n -1;j>=0;j--)
if(g.edges [i][j]!=0&&g.edges [i][j]!=INF)
{
p=(ArcNode *)malloc(sizeof(ArcNode));//创建一个节点*p
p->adjvex =j;
p->info =g.edges [i][j];
p->nextarc =G->adjlist [i].firstarc ;//将*p链到链表后
G->adjlist [i].firstarc =p;
}
G->n =g.n ;
G->e =g.e ;
}
void ListToMat1(ALGraph *G,MGraph &g)
{
int i,j;
ArcNode *p;
for(i=0;i<G->n ;i++) //g.edges[i][j]赋初值0
for(j=0;j<G->n ;j++)
if(i==j)
g.edges [i][j]=0;
else g.edges [i][j]=INF;
for(i=0;i<G->n ;i++)
{
p=G->adjlist[i].firstarc ;
while(p!=NULL)
{
g.edges [i][p->adjvex ]=p->info ;
p=p->nextarc ;
}
}
g.n =G->n ;
g.e =G->e ;
}
void DispMat1(MGraph g) //输出邻接矩阵g
{
int i,j;
for(i=0;i<g.n ;i++)
{
for(j=0;j<g.n ;j++)
if(g.edges [i][j]==INF)
printf(" %3s","∞");
else
printf(" %3d",g.edges [i][j]);
printf("\n");
}
}
void DispAdj1(ALGraph *G)
{
int i;
ArcNode *p;
for(i=0;i<G->n ;i++)
{
p=G->adjlist [i].firstarc ;
printf("%3d:",i);
while(p!=NULL)
{
printf("%3d(%d)",p->adjvex,p->info ) ;
p=p->nextarc;
}
printf("\n");
}
}
//非递归深度优先遍历
void DFS(ALGraph *G,int v)
{
ArcNode *p;
ArcNode *St[MAXV];
int top =-1,w,i;
for(i=0;i<G->n ;i++)
visited[i]=0; //顶点访问标志赋值为0
printf("%3d",v); //访问顶点
visited[v]=1; //标记访问过的顶点
top++;
St[top]=G->adjlist [v].firstarc ;
while(top>-1)
{
p=St[top];
top--;
while(p!=NULL)
{
w=p->adjvex ;
if(visited[w]==0)
{
printf("%3d",w);
visited[w]=1;
top++; //将顶点w的第一个顶点进栈
St[top]=G->adjlist [w].firstarc ;
break;
}
p=p->nextarc ;
}
}
printf("\n");
}
//深度优先遍历
void DFS1(ALGraph *G,int v)
{
ArcNode *p;
visited[v]=1;
printf("%3d",v);
p=G->adjlist [v].firstarc ; //p指向顶点v的第一条边的边头节点
while(p!=NULL)
{
if(visited[p->adjvex] ==0) //p->adjvex顶点未访问,递归访问他
DFS1(G,p->adjvex );
p=p->nextarc ; //指向下一条边的边头节点
}
}
//广度优先遍历
void BFS(ALGraph *G,int v)
{
ArcNode *p;
int queue[MAXV],front=0,rear=0; //定义循环队列,并初始化
int visited[MAXV]; //定义存放顶点的访问标志的数组
int w,i;
for(i=0;i<G->n ;i++)
visited[i]=0; //初始化标志数组
printf("%3d",v);
visited[v]=1;
rear=(rear+1)%MAXV; //也可以不用循环队列的,一般都不会溢出
queue[rear]=v; //v进队
while (front!=rear) //队列不空
{
front=(front+1)%MAXV;
w=queue[front]; //出队,并赋给w
p=G->adjlist [w].firstarc ; //找与顶点W邻接的第一个顶点
while(p!=NULL)
{
if(visited[p->adjvex ]==0)//当前访问的顶点没有访问过
{
printf("%3d",p->adjvex );
visited[p->adjvex ]=1;
rear=(rear+1)%MAXV;
queue[rear]=p->adjvex ;
}
p=p->nextarc ; //找下一个邻接顶点
}
}
printf("\n\n");
}
//利用普里姆算法求最小生成树
void Prim(MGraph g,int v)
{
int lowcost[MAXV],min,n=g.n ;
int closest[MAXV],i,j,k;
for(i=0;i<n;i++)
{
lowcost[i]= (g.edges[v][i]==0?INF:g.edges[v][i]);
closest[i]=0;
}
for(i=1;i<n;i++)
{
min=INF;
for(j=0;j<n;j++)
if(lowcost[j]!=0 && lowcost[j]<min)
{
min=lowcost[j];
k=j;
}
printf(" 边(%d,%d)权为:%d\n",closest[k],k,min);
lowcost[k]=0;
for(j=0;j<n;j++)
if(g.edges [k][j]!=0 && g.edges [k][j]<lowcost[j])
{
lowcost[j]=g.edges [k][j];
closest[j]=k;
}
}
}
void main()
{
int i,j;
MGraph g,g1;
ALGraph *G;
int A[8][8]={
{0,4,3,0,0,0,0,0},
{4,0,5,5,9,0,0,0},
{3,5,0,5,0,0,0,5},
{0,5,5,0,7,6,5,4},
{0,9,0,7,0,3,0,0},
{0,0,0,6,3,0,2,0},
{0,0,0,5,0,2,0,6},
{0,0,5,4,0,0,6,0}};
g.n =8;g.e =14;
for(i=0;i<g.n ;i++)
for(j=0;j<g.n ;j++)
g.edges [i][j]=A[i][j];
G=(ALGraph *)malloc(sizeof(ALGraph));
printf("图的邻接矩阵为:\n");
DispMat(g) ;
printf("\n无向图的邻接矩阵转换成邻接表:\n");
MarToList(g,G);
DispAdj(G);
printf("\n带权无向图的邻接矩阵转换成邻接表:\n");
MatToList1(g,G);
DispAdj1(G);
printf("\n无向图的邻接表换成邻接矩阵:\n");
LisrToMat(G,g1);
DispMat(g1);
printf("\n带权无向图的邻接表换成邻接矩阵:\n");
ListToMat1( G, g1);
DispMat1(g1);
printf("\n从顶点0开始的深度优先遍历(非递归):");
DFS(G,0);
for(i=0;i<G->n ;i++)
visited[i]=0;
printf("\n从顶点0开始的深度优先遍历(递归):");
DFS1(G,0);
printf("\n\n从顶点0开始的广度优先遍历:");
BFS(G,0);
printf("普里姆算法求解结果:\n");
Prim( g,0);}