数据结构 实验 图的存储与遍历

数据结构

实验 图的存储与遍历

一、实验目的

1、熟练掌握图的存储结构。

2、熟练掌握图的遍历及基本操作的实现。

二、实验原理

1、图存储结构及其应用。

三、实验设备

Win系统电脑一台

四、实验过程(程序清单)

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define Status int
#define VRType int
#define InfoType char
#define VertexType char
#define ERROR 0
#define OK 1
#define TRUE 1
#define FALSE 0
#define INFINITY 0 //最大值
#define MAX_VERTEX_NUM 20 //最大顶点个数
using namespace std;
bool visited[MAX_VERTEX_NUM];//访问标志数组
typedef struct ArcCell{//邻接矩阵(元素)类型
    VRType adj; //顶点关系(边),图用1\0表示是否相邻,网为权值
    InfoType *info; //边的相关信息指针
} ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct{//图的邻接矩阵类型
    VertexType vexs[MAX_VERTEX_NUM]; //顶点向量
    AdjMatrix arcs; //邻接矩阵
    int vexnum,arcnum; //图的顶点数和边数 
} Mgraph;
void (*VisitFunc)(Mgraph G,int v);//函数变量
void Input(InfoType *info){//录入边
    info=(char*)malloc(sizeof(char));
    scanf("%c",&*info);
}
Status LocateVex(Mgraph &G,VertexType u){//若G中存在点u,则返回该点在图中的位置
    int Loc;
    for(Loc=0;Loc<G.vexnum;Loc++){
        if(G.vexs[Loc]==u){
            return Loc;
        }
    }
    return -1;
}
Status CreateDG(Mgraph &G){//采用邻接矩阵表示法,构造有向图G
    int IncInfo,i,j,k;
    char v1,v2;
    printf("请输入图的顶点数:");
    scanf("%d",&G.vexnum);
    getchar();
    printf("请输入图的边数:");
    scanf("%d",&G.arcnum);
    getchar();
    printf("各边是否含有其他信息(1(有),0(没有):");
    scanf("%d",&IncInfo);
    getchar();
    for(i=0;i<G.vexnum;i++){
        printf("请输入第%d个顶点:",i+1);
        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=INFINITY;
            G.arcs[i][j].info=NULL;
        }
    }
    for(k=0;k<G.arcnum;k++){
        printf("请输入一条边连接的顶点:\n");
        printf("边的尾顶点:");//输入一条边依附的顶点
        scanf("%c",&v1);
        getchar();
        printf("边的头顶点:");
        scanf("%c",&v2);
        getchar();
        i=LocateVex(G,v1);
        j=LocateVex(G,v2);//确定v1和v2在G中的位置
        G.arcs[i][j].adj=1;//v1和v2的连接关系
        if(IncInfo){
            Input(G.arcs[i][j].info);//若边含有相关信息,则输入
        }
    }
    return OK;
}//CreateDG
Status CreateDN(Mgraph &G){//采用邻接矩阵表示法,构造有向网G
    int IncInfo,i,j,k,w;
    char v1,v2;
    printf("请输入图的顶点数:");
    scanf("%d",&G.vexnum);
    getchar();
    printf("请输入图的边数:");
    scanf("%d",&G.arcnum);
    getchar();
    printf("各边是否含有其他信息(1(有),0(没有)):");
    scanf("%d",&IncInfo);
    getchar();
    for(i=0;i<G.vexnum;++i){ //构造顶点向量
        printf("请输入第%d个顶点:",i+1);
        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=INFINITY;
            G.arcs[i][j].info=NULL;
        }
    }
    for(k=0;k<G.arcnum;++k){ //构造邻接矩阵
        printf("请输入一条边连接的顶点及权值:\n");
        printf("边的尾顶点:");//输入一条边连接的顶点及权值
        scanf("%c",&v1);
        getchar();
        printf("边的头顶点:");
        scanf("%c",&v2);
        getchar();
        printf("权值:");
        scanf("%d",&w);
        getchar();
        i=LocateVex(G,v1);
        j=LocateVex(G,v2);//确定v1和v2在G中的位置
        G.arcs[i][j].adj=w;//边<v1,v2>的权值
        if(IncInfo){
            Input(G.arcs[i][j].info);//若边含有相关信息,则输入
        }
    }
    return OK;
}//CreateDN
Status CreateUDG(Mgraph &G){//采用邻接矩阵表示法,构造无向图G
    int IncInfo,i,j,k;
    char v1,v2;
    printf("请输入图的顶点数:");
    scanf("%d",&G.vexnum);
    getchar();
    printf("请输入图的边数:");
    scanf("%d",&G.arcnum);
    getchar();
    printf("各边是否含有其他信息(1(有),0(没有)):");
    scanf("%d",&IncInfo);
    getchar();
    for(i=0;i<G.vexnum;++i){ //构造顶点向量
        printf("请输入第%d个顶点:",i+1);
        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=INFINITY;
            G.arcs[i][j].info=NULL;
        }
    }
    for(k=0;k<G.arcnum;++k){//构造邻接矩阵
        printf("请输入一条边连接的顶点:\n");
        printf("边的一个顶点:");//输入一条弧依附的顶点
        scanf("%c",&v1);
        getchar();
        printf("边的另一个顶点:");
        scanf("%c",&v2);
        getchar();
        i=LocateVex(G,v1);
        j=LocateVex(G,v2);//确定v1和v2在G中的位置
        G.arcs[i][j].adj=1;//v1和v2的连接关系
        if(IncInfo){
            Input(G.arcs[i][j].info);//若边含有相关信息,则输入
        }
        G.arcs[j][i]=G.arcs[i][j];//置<v1,v2>的对称边<v2,v1>
    }
    return OK;
}//CreateUDG
Status CreateUDN(Mgraph &G){//采用邻接矩阵表示法,构造无向网G
    int IncInfo,i,j,k,w;
    char v1,v2;
    printf("请输入图的顶点数:");
    scanf("%d",&G.vexnum);
    getchar();
    printf("请输入图的边数:");
    scanf("%d",&G.arcnum);
    getchar();
    printf("各边是否含有其他信息(1(有),0(没有)):");
    scanf("%d",&IncInfo);
    getchar();
    for(i=0;i<G.vexnum;++i){
        printf("请输入第%d个顶点:",i+1);
        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=INFINITY;
            G.arcs[i][j].info=NULL;
        }
    }//初始化邻接矩阵
    for(k=0;k<G.arcnum;++k){ //构造邻接矩阵
        printf("请输入一条边连接的顶点及权值:\n");
        printf("边的一个顶点:");//输入一条边连接的顶点及权值
        scanf("%c",&v1);
        getchar();
        printf("边的另一个顶点:");
        scanf("%c",&v2);
        getchar();
        printf("权值:");
        scanf("%d",&w);
        getchar();
        i=LocateVex(G,v1);
        j=LocateVex(G,v2);//确定v1和v2在G中的位置
        G.arcs[i][j].adj=w;//边<v1,v2>的权值
        if(IncInfo){
            Input(G.arcs[i][j].info);//若边含有相关信息,则输入
        }
        G.arcs[j][i]=G.arcs[i][j];//置<v1,v2>的对称边<v2,v1>
    }
    return OK;
}//CreateUDN
Status FirstAdjVex(Mgraph G,int v){//返回v的第一个邻接顶点
    int i;
    if(v>=0 && v<G.vexnum){
        for(i=0;i<G.vexnum;i++){
            if(G.arcs[v][i].adj){
                return i;
            }
        }
    }
    return -1;
}//FirstAdjVex
Status NextAdjVex(Mgraph G,int v,int w){//返回v的(相对于w的)下一个邻接顶点
    int i;
    if(v>=0 && v<G.vexnum){
        if(w>=0 && w<G.vexnum){
            for(i=w+1;i<G.vexnum;i++){
                if(G.arcs[v][i].adj){
                    return i;
                }
            }
        }
    }
    return -1;
}//NextAdjVex
void Print_JZ(Mgraph G){//打印矩阵
    int i,j;
    for(i=0;i<G.vexnum;i++){
        for(j=0;j<G.vexnum;j++){
            printf("%3d ",G.arcs[i][j].adj);
        }
        printf("\n");
    }
}
void Print(Mgraph G,int v){
    printf("%c",G.vexs[v]);
}
int main(){
    char Ch;
    Mgraph G;
    while(1){
        printf("*********图**********\n");
        printf("******1.建立有向图***\n");
        printf("******2.建立有向网***\n");
        printf("******3.建立无向图***\n");
        printf("******4.建立无向网***\n");
        printf("******0.返回*********\n");
        printf("输入图的种类:");
        scanf("%c",&Ch);
        getchar();
        switch(Ch)
        {
        case '1':
            CreateDG(G);//构造有向图G
            printf("有向图G的邻接矩阵为:\n");
            Print_JZ(G);
            getchar();
            break;
        case '2':
            CreateDN(G);//构造有向网G
            printf("有向网G的邻接矩阵为:\n");
            Print_JZ(G);
            getchar();
            break;
        case '3':
            CreateUDG(G);//构造无向图G
            printf("无向图G的邻接矩阵为:\n");
            Print_JZ(G);
            getchar();
            break;
        case '4':
            CreateUDN(G);//构造无向网G
            printf("无向网G的邻接矩阵为:\n");
            Print_JZ(G);
            getchar();
            break;
        case '0':
            exit(0);
            break;
        default:
            printf("选择错误!");
        }
        return 0;
    }
}

图的遍历(深度优先遍历/广度优先遍历)

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#define TRUE 1
#define FALSE 0
#define OVERFLOW -2
#define OK 1
#define ERROR 0
#define INFINITY INT_MAX//最大值“无穷”
#define MAX_VERTEX_NUM 20//最大顶点个数
typedef int Status;
typedef int Boolean;
typedef char VertexType[20];
typedef int  VRType;
//队列的操作
//队列的类型定义
typedef int QElemType;
typedef struct QNode{
	QElemType data;
	struct QNode *next;
}QNode,*QueuePtr;
typedef struct{
	QueuePtr front;
	QueuePtr rear;
}LinkQueue;
//初始化队列
Status InitQueue(LinkQueue *Q){
	(*Q).front=(*Q).rear=(QueuePtr)malloc(sizeof(QNode));
    if(!(*Q).front){
    	exit(OVERFLOW);
	}
    (*Q).front->next=NULL;
    return OK;
}
//判断队列是否为空
Status QueueEmpty(LinkQueue Q){
	if(Q.front==Q.rear){
		return TRUE;
	}
    else{
    	return FALSE;
    }
}
//入队列
Status EnQueue(LinkQueue *Q,QElemType e){
	QueuePtr p;
    p=(QueuePtr)malloc(sizeof(QNode));
    if(!p){
    	exit(OVERFLOW);
	}  
    p->data=e; p->next=NULL;
    (*Q).rear->next=p;
    (*Q).rear=p; 
    return OK;
}
//出队列
Status DeQueue(LinkQueue *Q, QElemType *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; 
}
//图的操作
//图的类型定义
typedef struct ArcCell{
    VRType adj;//图中有1/0表示是否有边,网中表示边上的权值
//  InfoType *info;//与边相关的信息
}ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct{
    VertexType vexs[MAX_VERTEX_NUM];//顶点向量
    AdjMatrix  arcs;//邻接矩阵
    int vexnum,arcnum;//图中当前顶点数和边数
}MGraph;
//顶点在顶点向量中的定位
int LocateVex(MGraph G,VertexType v){
	int i;
    for(i=0;i<G.vexnum;i++){
    	if(strcmp(v,G.vexs[i])==0){
    		break;
		} 
	}
    return i;
}
//建立无向图的邻接矩阵
void CreateGraph(MGraph *G){
	int i,j,k; VertexType v1,v2;
    printf("输入图的顶点数和边数:");
    scanf("%d %d",&(*G).vexnum,&(*G).arcnum);
    printf("输入各顶点:\n",(*G).vexnum);
    for(i=0;i<(*G).vexnum;i++){//输入顶点向量
        scanf("%s",(*G).vexs[i]);
	}
    for(i=0;i<(*G).vexnum;i++){//邻接矩阵初始化
        for(j=0;j<(*G).vexnum;j++){
        	(*G).arcs[i][j].adj=0;	
		}
    }
	printf("输入各边的结点为:\n",(*G).arcnum);
    for(k=0;k<(*G).arcnum;k++){   //输入无权图的边
        scanf("%s %s",v1,v2);
        i=LocateVex(*G,v1);j=LocateVex(*G,v2);
        (*G).arcs[i][j].adj=1;
        (*G).arcs[j][i]=(*G).arcs[i][j];
    }
}
//查找第1个邻接点
int FirstAdjVex(MGraph G,int v){
	int j,p=-1;
    for(j=0;j<G.vexnum;j++){
    	if(G.arcs[v][j].adj==1){
    		p=j; break;
	    }
    }
    return p;
}
//查找下一个邻接点 
int NextAdjVex(MGraph G,int v,int w){
	int j,p=-1;
    for(j=w+1;j<G.vexnum;j++){
    	if (G.arcs[v][j].adj==1){
    		p=j; break;
		}
	}
    return p;
}
//深度遍历
Boolean visited[MAX_VERTEX_NUM];  //设置全局的访问标志数组
void DFS(MGraph G, int v){
	int w;
    visited[v]=TRUE;
    printf("%s",G.vexs[v]);
    for(w=FirstAdjVex(G,v); w>=0; w=NextAdjVex(G,v,w)){
    	if(!visited[w]){
    		DFS(G,w);
		} 
	}
}
void DFSTraverse(MGraph G){
	int v;
    for(v=0;v<G.vexnum;v++){
    	visited[v]=FALSE;
	}
    for(v=0; v<G.vexnum; v++){
    	if (!visited[v]){
    		DFS(G,v);
		} 
	}
}
//广度遍历 
void BFSTraverse(MGraph G){
	int v,u,w; LinkQueue 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;
            printf("%s",G.vexs[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;
                        printf("%s",G.vexs[w]);
                        EnQueue(&Q,w);
			        }
		        }
            }
		}
	}
}
//主函数
int main(){
	int w;
    MGraph G;
    CreateGraph(&G);
    printf("\n深度优先遍历:"); DFSTraverse(G);//深度遍历 
    printf("\n广度优先遍历:"); BFSTraverse(G);//广度遍历 
}

拓扑排序

#include<stdio.h>
#include<stdlib.h>
#define MAX_VEXTEX_NUM 20  //最大顶点个数#define M 20
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10
#define OK 1
#define M 20
#define ERROR 0
typedef int ElemType;
typedef struct ArcNode{//定义表结点结构
	int adjvex; //与vi相邻接的顶点编号
    struct ArcNode *nextarc; //指向下一条弧(边)的指针
}ArcNode;
typedef struct VNode{//定义表头结点结构
    int data;
    ArcNode *firstarc; //指向第一条弧(边)的指针
}VNode, AdjList[MAX_VEXTEX_NUM];
typedef struct{ //定义邻接表结构
    AdjList vertices; //表头结点数组
    int vexnum, arcnum; //顶点和弧(边)的个数
}ALGraph;
typedef struct{ //构件栈
    ElemType *base;
    ElemType *top;
    int stacksize;
}SqStack;
void InitStack(SqStack *); //函数声明
int Pop(SqStack *, ElemType *);
void Push(SqStack *, ElemType);
int StackEmpty(SqStack *);
void CreatGraph(ALGraph *);
void FindInDegree(ALGraph, int *);
void TopologicalSort(ALGraph);
void InitStack(SqStack *S){//初始化栈
	S->base=(ElemType *)malloc(STACK_INIT_SIZE * sizeof (ElemType));
    if(!S->base){
    	printf("分配失败");
    	exit(1);
    }	
    S->top=S->base;
    S->stacksize=STACK_INIT_SIZE;
}
int Pop(SqStack *S,ElemType *e){//出栈操作
    if(S->top==S->base){
    	return ERROR;
    }
    *e=*--S->top;
    return 0;
}
void Push(SqStack *S, ElemType e){//进栈操作
    if (S->top - S->base >= S->stacksize){
    	S->base=(ElemType *)realloc(S->base,(S->stacksize+STACKINCREMENT) * sizeof(ElemType));
        if (!S->base){
        	printf("分配失败");
            exit(1);
        }
    S->top=S->base+S->stacksize;
    S->stacksize+=STACKINCREMENT;
    }
    *S->top++=e;
}
int StackEmpty(SqStack *S){//判断栈是否为空
    if(S->top==S->base){
    	return OK;
	}
    else{
    	return ERROR;
	}
}
void CreatGraph(ALGraph *G){//构建图
    int m,n,i;
    ArcNode *p;
    printf("请输入顶点数和边数:");
    scanf("%d %d",&G->vexnum,&G->arcnum);
    for(i=1;i<=G->vexnum;i++){
    	G->vertices[i].data=i;
    	G->vertices[i].firstarc=NULL;
    }
    for(i=1;i<=G->arcnum;i++){ //输入存在边的点集合
        printf("请输入存在边的两个顶点的序号:");
        scanf("%d %d", &n, &m);
        while(n<0 || n>G->vexnum || m<0 || m>G->vexnum){
        	printf("输入的顶点序号不正确,请重新输入:");
        	scanf("%d %d",&n,&m);
        }
        p=(ArcNode*) malloc(sizeof (ArcNode));
        if(p==NULL){
        	printf("分配失败");
        	exit(1);
        }
        p->adjvex=m;
        p->nextarc=G->vertices[n].firstarc;
        G->vertices[n].firstarc=p;
    }
}
void FindInDegree(ALGraph G, int indegree[]){//找入度为零的节点
    int i;
    for(i=1;i<=G.vexnum;i++){
    	indegree[i]=0;
    }
    for(i=1;i<=G.vexnum;i++){
        while(G.vertices[i].firstarc){
        	indegree[G.vertices[i].firstarc->adjvex]++;
        	G.vertices[i].firstarc=G.vertices[i].firstarc->nextarc;
        }
    }
}
//进行拓扑排序 ,拓扑排序结果不唯一 
void TopologicalSort(ALGraph G){
    int indegree[M];
    int i,k,n;
    int count=0;
    ArcNode *p;
    SqStack S;
    FindInDegree(G,indegree);
    InitStack(&S);
    for(i=1;i<=G.vexnum;i++) {
    	if(!indegree[i]){
    		Push(&S,i);
		}
    }
    printf("进行拓扑排序输出顺序为:\n"); //输出结果
    while(!StackEmpty(&S)){
    	Pop(&S,&n);
    	printf("%4d",G.vertices[n].data);
    	count++;
        for(p=G.vertices[n].firstarc;p!=NULL;p=p->nextarc){
        	k=p->adjvex;
            if(!(--indegree[k])){
            	Push(&S, k);
            }
        }
    }
    printf("\n");
    if(count<G.vexnum){
    	printf("该有向图有回路");
    } 
	else{
		printf("排序成功\n");
    }
}
int main(void){ //主函数
    ALGraph G;
    CreatGraph(&G);
    TopologicalSort(G);
    system("pause");
    return 0;
}

五、实验结果

图的遍历(深度优先遍历/广度优先遍历)

拓扑排序

六、实验心得

1、拓扑排序的结果不一定唯一。

2、掌握图的深度优先遍历、广度优先遍历、拓扑排序。

3、掌握有向图、有向网、无向图、无向网的邻接矩阵。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值