数据结构 图的基本操作实现
Posted Calm微笑
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构 图的基本操作实现相关的知识,希望对你有一定的参考价值。
实验题目: 图的基本操作实现
实验环境: Visual C++ 6.0
实验目的:掌握图的邻接矩阵和邻接表两个存储结构及表示。
掌握图的DFS和BFS两种遍历算法。
理解并掌握下述完整算法的基本思想以及算法实现方法:最小生成树算法、最短路径算法、拓扑排序算法及关键路径算法。
实验内容:1. 创建一个无向图,并分别对其进行DFS和BFS。
2. 实现最短路径、最小生成树、拓扑排序三种算法。
#include<cstdio>
#include<malloc.h>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define MaxInt 32767
#define MVNum 100
using namespace std;
typedef int Status;
bool visited[MVNum];
typedef struct
int vexs[MVNum];//顶点表
int arcs[MVNum][MVNum];//邻接矩阵
int vexnum,arcnum; //图的当前点数和边数
AMGraph;
Status CreateUDN(AMGraph &G)//用邻接矩阵建立无向网
int i,j,k,w;
int v1,v2;
printf("请输入总点数和总边数\\n");
cin>>G.vexnum>>G.arcnum;//输入总点数,总边数
for(i=0;i<G.vexnum;i++)
G.vexs[i]=i;
for(i=0;i<G.vexnum;i++)//初始化邻接矩阵
for(j=0;j<G.vexnum;j++)
G.arcs[i][j]=MaxInt;
if(i==j)
G.arcs[i][j]=0;
printf("请输入边的信息以及边的权值(顶点是0~n-1)\\n");
for(k=0;k<G.arcnum;++k)
cin>>v1>>v2>>w;
G.arcs[v1][v2]=w;
G.arcs[v2][v1]=w;
return OK;
Status CreateDirUDN(AMGraph &G)//用邻接矩阵建立有向网
int i,j,k,w;
int v1,v2;
printf("请输入顶点数和边数\\n");
cin>>G.vexnum>>G.arcnum;//输入总点数,总边数
for(i=0;i<G.vexnum;i++)
G.vexs[i]=i;
for(i=0;i<G.vexnum;i++)//初始化邻接矩阵
for(j=0;j<G.vexnum;j++)
G.arcs[i][j]=MaxInt;
if(i==j)
G.arcs[i][j]=0;
printf("请输入边的信息以及边的权值(顶点的范围为0~n-1)\\n");
for(k=0;k<G.arcnum;k++)
cin>>v1>>v2>>w;
G.arcs[v1][v2]=w;
return OK;
typedef struct ArcNode//边结点
int adjvex;//该边所指向的顶点的位置
struct ArcNode * nextarc;//指向下一条边的指针
//OtherInfo info;//和边相关的信息
ArcNode;
typedef struct VNode//顶点信息
int data;
ArcNode *firstarc;//指向第一条依附该顶点的边的指针
VNode,AdjList[MVNum];
typedef struct
AdjList vertices;
int visited[MVNum];
int vexnum,arcnum;//图的当前节点数和边数
ALGraph;
Status CreateUDG(ALGraph &G)//邻接表无向网
ArcNode *p1,*p2;
int v1,v2,i,j,k;
printf("请输入总点数和总边数\\n");
cin>>G.vexnum>>G.arcnum;
for(i=0;i<G.vexnum;++i)
G.vertices[i].data=i;//输入顶点值
G.vertices[i].firstarc=NULL;//初始化表头节点的指针域为空
printf("依次输入边的信息(顶点范围为0~n-1)\\n");
for(k=0;k<G.arcnum;++k)
cin>>i>>j;
p1=(ArcNode *)malloc(sizeof(ArcNode));
p1->adjvex=j;
p1->nextarc=G.vertices[i].firstarc;
G.vertices[i].firstarc=p1;//将新结点*P1插入顶点Vi的头部
p2=(ArcNode *)malloc(sizeof(ArcNode));
p2->adjvex=i;
p2->nextarc=G.vertices[j].firstarc;
G.vertices[j].firstarc=p2;
return OK;
Status CreateDirUDG(ALGraph &G)//邻接表有向网
ArcNode *p1,*p2;
int v1,v2,i,j,k;
printf("请输入总点数和总边数\\n");
cin>>G.vexnum>>G.arcnum;
for(i=0;i<G.vexnum;++i)
G.vertices[i].data=i;//输入顶点值
G.vertices[i].firstarc=NULL;//初始化表头节点的指针域为空
printf("依次输入边的信息(顶点范围为0~n-1)\\n");
for(k=0;k<G.arcnum;++k)
cin>>i>>j;
p1=(ArcNode *)malloc(sizeof(ArcNode));
p1->adjvex=j;
p1->nextarc=G.vertices[i].firstarc;
G.vertices[i].firstarc=p1;//将新结点*P1插入顶点Vi的头部
return OK;
void DFS_AL(ALGraph G,int v)
//图G为邻接表类型,从第V个顶点出发深度优先搜索遍历图G
ArcNode *p;
int w;
cout<<v;//访问第v个顶点
visited[v]=true;//标记该顶点已访问过
p=G.vertices[v].firstarc;//p指向V的边链表的第一个顶点
while(p!=NULL)//边结点非空
w=p->adjvex;//w是V的邻接点
if(!visited[w])//如果W未访问,则递归调用DFS__AL
DFS_AL(G,w);
p=p->nextarc;//p指向下一个边结点
typedef struct//队列的顺序储存
int *base;
int front;
int rear;
SqQueue;
Status InitQueue(SqQueue &Q)
//构造一个空的循环队列
Q.base=(int*)malloc(sizeof(int)*MVNum) ;
if(!Q.base)
exit(OVERFLOW);
Q.front=Q.rear=0;
return OK;
Status EnQueue(SqQueue &Q,int v)
//插入元素v为Q的新队尾元素
if((Q.rear+1)%MVNum==Q.front)
return ERROR;
Q.base[Q.rear]=v;//新元素插入队尾
Q.rear=(Q.rear+1)%MVNum;//队尾指针加一
return OK;
Status DeQueue(SqQueue &Q,int &v)
//删除Q的队头元素,用V返回其值
if(Q.front==Q.rear)
return ERROR;
v=Q.base[Q.front];//保存队头元素
Q.front=(Q.front+1)%MVNum;//队头指针加一
return OK;
Status QueueEmpty(SqQueue &Q)//判断队列是否为空
if(Q.front==Q.rear)
return 1;
return 0;
void Visit(ALGraph &G,int i)
printf(" %d",G.vertices[i].data) ;
G.visited[i]=1; //将访问标志置为1
void BFS_AL(ALGraph G,int v)
//按广度优先非递归遍历连通图G
SqQueue Q;
ArcNode *w;
int u;
cout<<v;//访问第v个顶点
visited[v]=true;//标记v已经访问过
InitQueue(Q);//初始化队列Q
EnQueue(Q,v);//V进队
while(!QueueEmpty(Q))//队列非空
DeQueue(Q,u);//队头元素出队并置为u
for(w=G.vertices[u].firstarc;w;w=w->nextarc)
//依次检查u的所有邻接点w
if(!G.visited[w->adjvex] )
Visit(G,w->adjvex);
EnQueue(Q,w->adjvex);
printf("\\n");
struct node
int adjvex;//最小边在U的那个顶点
int lowcost;//最小边上的权值
closedge[MVNum];
void MiniSpanTree_Prim(AMGraph G,int k)
//无向网G以邻接矩阵形式储存,从顶点u出发构造G的最小生成树T,输出T的各条边
//k=LocateVex(G,u);//k为顶点u的下标
int i,j,u0,v0,minn;
for(j=0;j<G.vexnum;j++)//对V-U的每个顶点vj,初始化closedge[j]
if(j!=k)
closedge[j].adjvex=k;
closedge[j].lowcost=G.arcs[k][j];
closedge[k].lowcost=0;//初始,U=u;
for(i=1;i<G.vexnum;++i)
//选择其余n-1个顶点,生成n-1条边
minn=MaxInt;
for(j=0;j<G.vexnum;j++)
if(closedge[j].lowcost>0)
if(closedge[j].lowcost<minn)
k=j;
minn=closedge[j].lowcost;
u0=closedge[k].adjvex;//u0为最小边的一个顶点,u0属于U
v0=G.vexs[k];//v0为最小边的另一个顶点,v0属于V-U
cout<<u0<<v0;//输出当前最小边
printf("\\n");
closedge[k].lowcost=0;//第K个顶点并入U集
for(j=0;j<G.vexnum;++j)
if(G.arcs[k][j]<closedge[j].lowcost)//新顶点并入U集后重新选择最小边
closedge[j].adjvex=G.vexs[k];
closedge[j].lowcost=G.arcs[k][j];
void ShortestPath_DIJ(AMGraph G,int v0)//最短路径
int n,v,i,j,minn,w;
bool S[1100];
int Path[1100],D[1100];
n=G.vexnum;
for(v=0;v<n;++v)//顶点初始化
S[v]=false;
D[v]=G.arcs[v0][v];
if(D[v]<MaxInt)
Path[v]=v0;
else
Path[v]=-1;
S[v0]=true;
D[v0]=0;
//求v0到某个顶点v的最短路径 ,将v加到s集
for(i=1;i<n;++i)
minn=MaxInt;
for(w=0;w<n;++w)
if(!S[w]&&D[w]<minn)
v=w;
minn=D[w];
S[v]=true;
for(w=0;w<n;++w)
if(!S[w]&&(D[v]+G.arcs[v][w]<D[w]))
D[w]=D[v]+G.arcs[v][w];
Path[w]=v;
for(i=1;i<n;++i)
printf("%d %d %d\\n",G.vexs[0],G.vexs[i],D[i]);
typedef struct
int *base;
int *top;
int stacksize;
SqStack;
Status InitStack(SqStack &S)//初始化
S.base=(int*)malloc(sizeof(int)*MVNum);
if(!S.base)
exit(OVERFLOW);
S.top=S.base;
S.stacksize=MVNum;
return OK;
Status Push(SqStack &S,int e)//入栈
if(S.top-S.base==S.stacksize)
return ERROR;//栈满
*S.top++=e;//元素e压入栈顶,栈顶指针加1;
return OK;
Status Pop(SqStack &S,int &e)//出栈
if(S.top==S.base)//栈空
return ERROR;
e=*--S.top;//栈顶指针减一,将栈顶元素赋给e;
return OK;
Status StackEmpty(SqStack S)//判断栈空
if(S.top==S.base)
return 1;
return 0;
void Findindegree(ALGraph G,int indegree[]) //求入度
int i;
for(i=0;i<G.vexnum;i++)
indegree[i]=0;
for(i=0;i<G.vexnum;i++)
while(G.vertices[i].firstarc)
indegree[G.vertices[i].firstarc->adjvex]++;
G.vertices[i].firstarc=G.vertices[i].firstarc->nextarc;
Status TopologicalSort(ALGraph &G)//拓扑排序
SqStack S;
int i,m,k,v;
int indegree[1100];
ArcNode *p;
InitStack(S);
Findindegree(G,indegree);
printf("各顶点的入度为:\\n");
for(i=0;i<G.vexnum;i++)
printf("%d ",indegree[i]);
printf("\\n");
for(i=0;i<G.vexnum;i++)
if(indegree[i]==0)
Push(S,i);
m=0;
while(!StackEmpty(S))
Pop(S,v);
printf("%d ",v);
m++;
for(p=G.vertices[v].firstarc;p!=NULL;p=p->nextarc)
k=p->adjvex;
if(!(--indegree[k]))
Push(S,k);
printf("\\n");
printf("排序成功\\n");
int main()
AMGraph G,T;
ALGraph M,N,R;
int v,k;
printf("************************\\n");
printf("1.DFS遍历邻接表无向网\\n");
printf("2.BFS遍历邻接表无向网\\n");
printf("3.邻接矩阵无向网生成最小生成树\\n");
printf("4.邻接矩阵有向网生成最短路径\\n");
printf("5.邻接表有向网生成拓扑序列\\n");
printf("0.退出\\n");
printf("************************\\n");
int choose=-1;
while(choose)
printf("请选择: \\n");
scanf("%d",&choose);
switch(choose)
case 1:
printf("请先创建一个无向网邻接链表\\n:");
CreateUDG(M);
printf("创建成功\\n");
printf("请输入遍历的起点\\n");
scanf("%d",&v);
DFS_AL(M,v);
break;
case 2:
printf("请先创建一个无向图邻接链表\\n");
CreateUDG(N);
printf("创建成功\\n");
printf("请输入遍历的起点\\n");
scanf("%d",&v);
BFS_AL(N,v);
break;
case 3:
printf("请先创建一个无向网邻接矩阵\\n");
CreateUDN(G);
printf("创建成功\\n");
printf("请输入起点\\n");
scanf("%d",&k);
MiniSpanTree_Prim(G,k);
break;
case 4:
printf("请创建一个有向网邻接矩阵\\n");
CreateDirUDN(T);
printf("创建成功\\n");
printf("请输入起点\\n");
scanf("%d",&k);
ShortestPath_DIJ(T,k);
break;
case 5:
printf("请先创建一个有向网邻接链表\\n");
CreateDirUDG(R);
printf("创建成功\\n");
TopologicalSort(R);
break;
return 0;
以上是关于数据结构 图的基本操作实现的主要内容,如果未能解决你的问题,请参考以下文章
用邻接表表示图的广度优先搜索时的存储结构,通常采用()结构来实现算法