数据结构 实验四 图
数据结构 实验四 图
这次给出图论部分的数据结构相关代码,由于图结构不像树结构那样具有明显的层次性,较实验三的二叉树来说会复杂一些;在图的存储结构中,邻接矩阵的存储方式较为简单明了,但是在实际开发中往往由于其会导致占用大量的内存空间而被舍弃,但邻接表这样的链式结构就解决了这一的问题,所以对邻接表的掌握较为重要。
下面放出图的相关代码:
#include <stdio.h> #include <stdlib.h> /*包含数据结构的预定义常量和类型P10 */ #include "Datahead.h" /* P161 图的数组(邻接矩阵)存储表示*/ #define INFINITY INT_MAX /*无穷大 */ #define INT_MAX 999 /*最大整数 */ #define MAX_VERTEX_NUM 20 /*图的最大顶点数*/ typedef enum{DG,DN,UDG,UDN} GraphKind; /*有向图,有向网,无向图,无向网*/ typedef int VRType; /*网络权值暂定为整数型*/ typedef char InfoType; /*备用*/ typedef char VertexType; /*顶点名称,字符型*/ typedef struct ArcCell{ VRType adj; /*顶点关系类型:无向图,用0或1表示是否相邻;对于带权图,则为权值类型*/ InfoType *info; /*该弧相关信息的指针*/ }ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; typedef struct{ VertexType vexs[MAX_VERTEX_NUM]; /*顶点向量*/ AdjMatrix arcs; /*邻接矩阵*/ int vexnum,arcnum; /*图的当前顶点数和弧数*/ GraphKind kind; /*图的种类标志*/ }MGraph; /*P163 图的邻接表存储表示*/ typedef struct ArcNode{ int adjvex; struct ArcNode *nextarc; InfoType *info; }ArcNode; typedef struct VNode{ VertexType data; ArcNode *firstarc; }VNode,AdjList[MAX_VERTEX_NUM]; typedef struct{ AdjList vertices; int vexnum,arcnum; int kind; }ALGraph; /*算法7.4 7.5 深度遍历图*/ /* --- 算法7.4和7.5使用的全局变量 --- */ bool visited[MAX_VERTEX_NUM]; /* 访问标志数组 */ Status (* VisitFunc)(int v); /* 函数变量 */ /*p61队列定义*/ typedef struct QNode{ int data; /*图中结点用结点数组中的位置表示,为整数*/ struct QNode *next; }QNode, *QueuePtr; typedef struct{ QueuePtr front; QueuePtr rear; }LinkQueue; /*函数原型声明*/ Status CreateGraph(MGraph *G); Status CreateDG(MGraph *G); Status CreateDN(MGraph *G); Status CreateUDG(MGraph *G); Status CreateUDN(MGraph *G); void OutputMG(MGraph G); int LocateVex(MGraph G, VertexType v1); Status CreateALGraph(MGraph *M, ALGraph *AL); void OutputAL(ALGraph AL); void DFSTraverse(ALGraph G, Status (*Visit)(int v)); void DFS(ALGraph G, int v); int FirstAdjVex(ALGraph G, int v); int NextAdjVex(ALGraph G, int v, int w); Status PrintInt(int e); /*Visit 函数*/ void BFSTraverse(ALGraph G, Status (*Visit)(int v )); /* 算法7.6 */ Status InitQueue(LinkQueue *Q); Status EnQueue(LinkQueue *Q,int e); Status DeQueue(LinkQueue *Q,int *e); Status QueueEmpty(LinkQueue Q); MGraph *p; MGraph G; /*全局变量 图G*/ ALGraph *A,AL; /*邻接表变量*/ // 主函数 void main() { p=&G; system("graftabl 936");/*调用MS_DOS中文支持*/ printf("\n**********************图**********************\n\n"); if ( CreateGraph(p) ) OutputMG(G); A=&AL; if ( CreateALGraph(p, A) ) OutputAL(AL); printf("\n深度遍历为:"); DFSTraverse(AL, PrintInt); printf("\n广度遍历为:"); BFSTraverse (AL, PrintInt ); getchar(); } Status CreateGraph(MGraph *G){ /* 算法7.1 */ /* 采用数组(邻接矩阵)表示法,构造图G*/ int k; printf("请选择创建图的类型 \t1:有向图DG;\n\t\t\t2:有向网DN;\n\t\t\t3:无向图UDG;\n\t\t\t4:无向网UDN.\n"); scanf("%d", &k); switch(k){ case 1: return CreateDG(G); /* 构造有向图G */ case 2: return CreateDN(G); /* 构造有向网G */ case 3: return CreateUDG(G); /* 构造无向图G */ case 4: return CreateUDN(G); /* 构造无向网G,算法7.2 */ default : return ERROR; } } /* CreateGraph */ Status CreateDG(MGraph *G) {/* 改造自算法 7.2 */ /* 采用数组(邻接矩阵)表示法,构造有向图 */ int i,j,k,w; VertexType v1,v2; printf("请输入顶点个数G->vexnum :" ); scanf("%d",&G->vexnum); printf("请输入弧的条数G->arcnum :"); scanf("%d",&G->arcnum); getchar(); /*** 加上此句getchar()!!! ***/ /* scanf("%d,%d,%d",&G.vexnum, &G.arcnum, &IncInfo); */ for (i=0; i<G->vexnum; i++ ) { printf("请输入顶点G->vexs[%d]的名称(字符型):",i); scanf("%c",&G->vexs[i]); getchar(); } /* 构造顶点向量 */ for (i=0; i<G->vexnum; ++i ) /* 初始化邻接矩阵 ,全部赋值为0*/ for (j=0; j<G->vexnum; ++j ) { G->arcs[i][j].adj = 0; /* {adj,info} */ G->arcs[i][j].info= NULL; } for (k=0; k<G->arcnum; ++k ) { /* 构造邻接矩阵 printf("v1 (char) : "); scanf("%c", &v1);getchar(); printf("v2 (char) : "); scanf("%c", &v2);getchar(); printf("w (int) : " ); scanf("%d", &w); getchar(); */ printf("请依次输入弧尾、弧头顶点名称(如,a b):" ); scanf("%c %c", &v1,&v2);getchar(); /* 输入一条边依附的顶点及权值 */ i = LocateVex(*G, v1); j = LocateVex(*G, v2); /* 确定v1和v2在G中位置 */ G->arcs[i][j].adj = 1; /* 弧<v1,v2>的权值为1,表示两点相邻接 */ /* if (IncInfo) scanf(G.arcs[i][j].info); /* 输入弧含有相关信息 */ } G->kind=DG; return OK; } /* CreateDG */ Status CreateDN(MGraph *G) {/* 改造自算法 7.2 */ /* 采用数组(邻接矩阵)表示法,构造有向图 */ int i,j,k,w; VertexType v1,v2; printf("请输入顶点个数G->vexnum :" ); scanf("%d",&G->vexnum); printf("请输入弧的条数G->arcnum :"); scanf("%d",&G->arcnum); getchar(); /*** 加上此句getchar()!!! ***/ /* scanf("%d,%d,%d",&G.vexnum, &G.arcnum, &IncInfo); */ for (i=0; i<G->vexnum; i++ ) { printf("请输入顶点G->vexs[%d]的名称(字符型):",i); scanf("%c",&G->vexs[i]); getchar(); } /* 构造顶点向量 */ for (i=0; i<G->vexnum; ++i ) /* 初始化邻接矩阵 ,全部赋值为0*/ for (j=0; j<G->vexnum; ++j ) { G->arcs[i][j].adj = 0; /* {adj,info} */ G->arcs[i][j].info= NULL; } for (k=0; k<G->arcnum; ++k ) { /* 构造邻接矩阵*/ printf(" 请依次输入第%d条边依附的两个顶点,以及该边的权值:", k+1); scanf("%c %c %d", &v1, &v2, &w); getchar(); i = LocateVex(*G, v1); j = LocateVex(*G, v2); G->arcs[i][j].adj = w; /* if (IncInfo) scanf(G.arcs[i][j].info); /* 输入弧含有相关信息 */ } G->kind=DN; return OK; } /* CreateDN */ Status CreateUDG(MGraph *G) {/* 改造自算法 7.2 */ /* 采用数组(邻接矩阵)表示法,构造无向图 */ int i,j,k; VertexType v1,v2; printf("请输入顶点个数G->vexnum :" ); scanf("%d",&G->vexnum); printf("请输入弧的条数G->arcnum :"); scanf("%d",&G->arcnum); getchar(); /*** 加上此句getchar()!!! ***/ /* scanf("%d,%d,%d",&G.vexnum, &G.arcnum, &IncInfo); */ for (i=0; i<G->vexnum; i++ ) { printf("请输入顶点G->vexs[%d]的名称(字符型):",i); scanf("%c",&G->vexs[i]); getchar(); } /* 构造顶点向量 */ for (i=0; i<G->vexnum; ++i ) /* 初始化邻接矩阵 ,全部赋值为0*/ for (j=0; j<G->vexnum; ++j ) { G->arcs[i][j].adj = 0; /* {adj,info} */ G->arcs[i][j].info= NULL; } for (k=0; k<G->arcnum; ++k ) { /* 构造邻接矩阵 printf("v1 (char) : "); scanf("%c", &v1);getchar(); printf("v2 (char) : "); scanf("%c", &v2);getchar(); printf("w (int) : " ); scanf("%d", &w); getchar(); */ printf("请依次输入弧尾、弧头顶点名称(如,a b):" ); scanf("%c %c", &v1,&v2);getchar(); /* 输入一条边依附的顶点及权值 */ i = LocateVex(*G, v1); j = LocateVex(*G, v2); /* 确定v1和v2在G中位置 */ G->arcs[i][j].adj = 1; /* 弧<v1,v2>的权值为1,表示两点相邻接 */ /* if (IncInfo) scanf(G.arcs[i][j].info); /* 输入弧含有相关信息 */ G->arcs[j][i].adj = G->arcs[i][j].adj; /* 置<v1,v2>的对称弧<v2,v1> */ } G->kind=UDG; return OK; } /* CreateUDG */ Status CreateUDN(MGraph *G) {/* 算法 7.2 */ /* 采用数组(邻接矩阵)表示法 */ int i, j, k; VRType w; VertexType v1, v2; printf("请输入顶点个数G->vexnum :" ); scanf("%d", &G->vexnum); printf("请输入弧的条数G->arcnum :"); scanf("%d", &G->arcnum); getchar(); // 构造顶点向量 for( i = 0; i < G->vexnum; i++ ) { printf("请输入顶点G->vexs[%d]的名称(字符型):", i); scanf("%c", &G->vexs[i]); getchar(); } // 初始化邻接矩阵 for( i = 0; i < G->vexnum; i++ ) { for( j = 0; j < G->vexnum; j++ ) { G->arcs[i][j].adj = 0; G->arcs[i][j].info = NULL; } } // 构造邻接矩阵 for( k = 0; k < G->arcnum; ++k ) { printf(" 请依次输入第%d条边依附的两个顶点,以及该边的权值:", k+1); scanf("%c %c %d", &v1, &v2, &w); getchar(); i = LocateVex(*G, v1); j = LocateVex(*G, v2); G->arcs[i][j].adj = w; G->arcs[j][i] = G->arcs[i][j]; } G->kind = ::UDN; return OK; } int LocateVex(MGraph G,VertexType v1){ int i; for (i = 0;i <= G.vexnum; i++) { if (v1 == G.vexs[i]) return i; } return 0; } /*建立无向图邻接矩阵*/ /*输出邻接矩阵*/ void OutputMG(MGraph G) { int i,j; printf("\n邻接矩阵为:"); for(i=0;i<G.vexnum;i++) { printf("\n"); for(j=0;j<G.vexnum;j++) printf("%5d",G.arcs[i][j]); } } /*创建邻接表,数据来源于已知的邻接矩阵*/ Status CreateALGraph(MGraph *M, ALGraph *AL){ int i,j; ArcNode *head,*p; AL->vexnum=M->vexnum; AL->arcnum=M->arcnum; AL->kind=M->kind; for (i=0;i<M->vexnum;i++) AL->vertices[i].data=M->vexs[i]; head = (ArcNode *)malloc(sizeof(ArcNode)); /*单链表 头指针*/ for (i=0;i<M->vexnum;i++) {head->nextarc=NULL; for (j=0;j<M->vexnum;j++) { if ((M->arcs[i][j].adj!=INFINITY) &&(M->arcs[i][j].adj!=0)) {p = (ArcNode *)malloc(sizeof(ArcNode)); p->info=M->arcs[i][j].info; p->nextarc=head->nextarc; p->adjvex=j;/*j顶点*/ head->nextarc=p; /*逆序插入各弧*/ } } AL->vertices[i].firstarc = head->nextarc; } free(head); return OK; } void OutputAL(ALGraph AL){ int i,j; ArcNode *p; printf("\n邻接表为:"); for (i=0;i<AL.vexnum;i++) { printf("\n顶点%c->",AL.vertices[i].data); p=AL.vertices[i].firstarc; while(p) /*输出单链表*/ { printf("%5d",p->adjvex); p=p->nextarc; } } } void DFSTraverse(ALGraph G, Status (*Visit)(int v)) { /* 算法7.4 */ /* 对图G作深度优先遍历。 对尚未访问的顶点调用DFS */ int v; VisitFunc = Visit; for( v = 0; v < G.vexnum; v++ ) visited[v] = FALSE; // 初始化访问标记数组 for( v = 0; v < G.vexnum; v++ ) { if( !visited[v] ) DFS(G, v); // 对尚未访问的顶点调用DFS } } void DFS(ALGraph G, int v) { /* 算法7.5 */ /* 从第v个顶点出发递归地深度优先遍历图G。*/ visited[v] = TRUE; VisitFunc(v); int w; for( w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w) ) { if( !visited[w] ) DFS(G, w); } } int FirstAdjVex(ALGraph G,int v){ ArcNode *p; p = G.vertices[v].firstarc; if(p != NULL) return p->adjvex; else return -1;/*p为空*/ } int NextAdjVex(ALGraph G,int v,int w){ ArcNode *p; p = G.vertices[v].firstarc; while(p){ if ((p->adjvex == w)&&(p->nextarc != NULL)) return p->nextarc->adjvex; p = p->nextarc; } return -1; } // 此处改写了 Visit 函数,改为输出顶点名称,即data中的信息 Status PrintInt(int e){ /*Visit 函数*/ //printf(" %d",e); printf(" %c",AL.vertices[e].data); //输出值,以强调visit函数 return OK; } void BFSTraverse(ALGraph G, Status (*Visit)(int v )) {/* 算法7.6 */ /* 按广度优先非递归遍历图G。使用辅助队列Q和访问标志数组visited。 */ int v, u, w; LinkQueue Q, *pQ; pQ = &Q; for( v = 0; v < G.vexnum; v++ ) visited[v] = FALSE; // 初始化访问标记数组 InitQueue(&Q); // 置空的辅助队列 for( v = 0; v < G.vexnum; v++ ) { if( !visited[v] ) { visited[v] = TRUE; Visit(v); EnQueue(&Q, v); while (!QueueEmpty(Q)) { DeQueue(&Q, &u); for( w = FirstAdjVex(G, u); w >= 0; w = NextAdjVex(G, u, w) ) if( !visited[w] ) { visited[w] = TRUE; Visit(w); EnQueue(&Q, w); } } } } } /* BFSTraverse */ Status InitQueue(LinkQueue *Q){ /*生成头结点*/ Q->front = Q->rear =(QueuePtr)malloc(sizeof(QNode)); Q->front->next = NULL; return OK; } Status EnQueue(LinkQueue *Q, int e){ QueuePtr p; p=(QueuePtr)malloc(sizeof(QNode)); p->data=e; p->next=NULL; Q->rear->next=p; Q->rear=p; return OK; } Status DeQueue(LinkQueue *Q,int *e){ QueuePtr p; if (Q->front==Q->rear) return ERROR; p=Q->front->next; *e=p->data; Q->front->next=p->next; if (Q->rear==p) Q->rear=Q->front; free(p); return OK; } Status QueueEmpty(LinkQueue Q){ if (Q.rear==Q.front) return TRUE; else return FALSE; }
可以直接复制上述代码,也可也去我的网盘下载该cpp源文件(含”DataHead.h“头文件)