Bootstrap

C语言 数据结构 图的储存、遍历、简单应用

C语言 数据结构 图的储存、遍历、简单应用

内容:

1,创建图(邻接矩阵和邻接链表两种方法)

2,图的深度和广度优先搜索结果

3,判断图是否为连通图

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define MVNum 100         //最大顶点数
#define MAXSIZE 100
typedef char VerTexType;  //设顶点的数据类型为字符型 
typedef int ArcType;      //假设边的权值类型为整形
typedef int QELemType;   //队列元素类型 

//邻接矩阵存储22222 
//先输入总项数和总边数
//依次输入点的信息存入定点表中 
//初始化邻接矩阵,使每个权值初始化为极大值 
typedef struct{
	VerTexType vexs[MVNum];       //顶点表 
	ArcType arc[MVNum][MVNum];    //邻接矩阵   图0/1  网:无穷/权值 
	int vexnum,arcnum;            //图的当前点数和边数
	 
} AMGragh;    //Adjacency Matrix ->邻接矩阵
int LocationVex(AMGragh *G,int num);  //在顶点表中查找num的位置 
int CreateUDN(AMGragh *G);           
void showGragh(AMGragh *G);
 
//邻接表存储
// 输入总点数和总边数
// 建立顶点表:依次输入点的信息存入顶点表中,使每个表头节点的指针域初始化为NULL
//创建邻接表:依次输入每条边依附的两个节点,确定两个顶点的序号i和j,建立边节点 
// 将此边结点分别插入到v(i)和v(j)对应的两个边链表的头部 
 typedef struct ArcNode{       //边节点 
 	int adjVex;                //该边所指向的顶点的位置  
	struct ArcNode *nextarc;   //指向下一条边的指针  
	int info;                  //和边相关的信息 权值等 
 }ArcNode;
 typedef struct VNode{     //顶点节点 
 	VerTexType data;       //顶点信息
	ArcNode *firstarc;     //指向第一条依附该顶点的边的指针 
 }VNode,AdjList;           //AdjList:邻接表类型 
 typedef struct{                 //图 
 	VNode vertices[MVNum];       //vertext的复数
	int vexnum,arcnum;           //图的当前顶点数和弧度 
 }ALGragh;
int LLocationVex(ALGragh *G,int num); 
int CreateUDG_L(ALGragh *G); 
void showGragh_L(ALGragh *G); 
void DFS(ALGragh *G, int v0);
void BFS(ALGragh *G, int v0);
void TraverseG(ALGragh *G);
int connect(ALGragh *G);
void pathdfs(ALGragh *G,int i,int j);
//循环队列顺序存储结构
typedef struct{
	QELemType data[MAXSIZE];
	int front;  //头指针 
	int rear;   //尾指针,若队列不为空,指向队尾元素的下一个位置 
}SqQueue; 

//队列初始化
void InitQueue(SqQueue *Q){
	Q->front=0;
	Q->rear=0;
} 
//队列判空
int QueueEmpty(SqQueue *Q){
	if(Q->front==Q->rear)
	return 1;
	return 0;
}
//循环队列入队操作
int EnQueue(SqQueue *Q,QELemType e){
	if((Q->rear+1)%MAXSIZE==Q->front)   //队满
	    return -1;
	Q->data[Q->rear]=e;  
	Q->rear=(Q->rear+1)%MAXSIZE;  
	return 0;  
}
//循环队列出队操作
int DeQueue(SqQueue *Q,QELemType *e){  //用e返回队尾元素 
	if(Q->front==Q->rear)     //判断队空 
	   return -1;
	*e=Q->data[Q->front];
	Q->front=(Q->front+1)%MAXSIZE;
	return 0; 
} 
 
int main(){
	printf("请选择存储方式:1-邻接矩阵存储 2-邻接表存储");
	int key;
	scanf("%d",&key);
	switch(key){
		case 1:{
			AMGragh G;
			CreateUDN(&G);
			showGragh(&G);
			break;
		}
		case 2:{
			ALGragh G;
            CreateUDG_L(&G);
            showGragh_L(&G);
			int num=connect(&G);
	        if(num==1) printf("\n该图为连通图\n");
	        else printf("\n该图不连通\n"); 
	        int num1, num2,i,j;
            printf("请输入两个元素:");
            scanf("%d %d", &num1, &num2);
            i=LLocation(&G,num1);
            i=LLocation(&G,num1);
            printf("简单路径为:");
            pathdfs(graph, i, j);
            printf("\n");
			break;
		}
	}
}

/*连通图的简单路径(类dfs) */
void pathdfs(ALGragh *G,int i,int j){
    EdgeNode *p;
    int s,w;
    visited[i] = 1;           //将顶点i加入当前路径
    path[++top] = G->list[i].data;
    if(!flag && path[top] == G->list[j].data) {
        flag = 1;   //存在顶点i到顶点j的路径
    }
    if(flag)       //找到
    {
    //输出当前路径上所有顶点
        printf("\n");
    for(s=1;s<=top;s++)
        printf("%d\t",path[s]);
        flag = 0;
    }
    else
        for(p = G->list[i].firstEdge; p; p = p->next)
    {
        w = p->indexVertex;
        if(!visited[w])
        pathdfs(G,w,j);
    }
        visited[i]=0;         //每当顶点i回溯时,把visited[i]置为0,下次可通过顶点i寻找其他可能到达j的路径
        top--;               //删除顶点i
 
}

  int CreateUDG_L(ALGragh *G){
  	int v1,v2;
	  int num,i,j;
  	printf("请输入总顶点和总边数:");
  	scanf("%d %d",&G->vexnum,&G->arcnum);
  	for(int l=0;l<G->vexnum;l++){         //输入各个顶点 
  		scanf("%d",&G->vertices[l].data);
//  		printf("%d",G->vertices[l].data);
  		G->vertices[l].firstarc=NULL;     //初始化表头节点的指针域 
	  }
	printf("请输入一条边所依附的顶点及边的权值\n"); 
	for(int k=0;k<G->arcnum;k++){         //输入各边,构造邻接表 
		scanf("%d %d %d",&v1,&v2,&num);
		i=LLocationVex(G,v1); //查找 
		j=LLocationVex(G,v2);
		ArcNode *p1=(ArcNode *)malloc(sizeof(struct ArcNode));
		p1->adjVex=j;       //邻接点序号为j
		p1->info=num;
		p1->nextarc=G->vertices[i].firstarc;
		G->vertices[i].firstarc=p1;    //将新节点*p1插入顶点vi的边表头部  头插法  //无向网
		ArcNode *p2=(ArcNode *)malloc(sizeof(ArcNode));                                                                                                                                                                                                              
		p2->adjVex=i;
		p2->info=num; 
		p2->nextarc=G->vertices[j].firstarc;
		G->vertices[j].firstarc=p2; 
	}
  }
 
 int LLocationVex(ALGragh *G,int num){
 	int i;
 	for(i=0;i<G->vexnum;i++){
 		if(G->vertices[i].data==num){
 			break;
		 }
	 }
	return i;
 } 
 
//展示邻接表存储
void showGragh_L(ALGragh *G){
	   printf("邻接表储存:\n");
	   for(int i=0;i<G->vexnum;i++){
     	printf("%d ->",G->vertices[i].data);
     	for(ArcNode *j=G->vertices[i].firstarc;j!=NULL;j=j->nextarc){
     		printf("%d  ",G->vertices[j->adjVex].data);
		 }
        printf("\n");
	 }
	 printf("\n");
	TraverseG(G);	 
} 
//连通图的深度优先搜索
int visited[MVNum]={0};   //访问标志数组 
void DFS(ALGragh *G, int v0){
	printf("%d",G->vertices[v0].data);
	visited[v0]=1;  
	ArcNode *p=G->vertices[v0].firstarc;
	while(p!=NULL){
		if(!visited[p->adjVex]){
			DFS(G,p->adjVex);
		}
		p=p->nextarc;
	}
}  

void BFS(ALGragh *G, int v0){
	QELemType u;
	printf("%d",G->vertices[v0].data);
	visited[v0]=1;
	SqQueue Q;
	InitQueue(&Q);
	EnQueue(&Q,v0);
	while(!QueueEmpty){  //队列非空
	DeQueue(&Q,&u);      //队头元素出队并置为u 
	for(ArcNode *w=G->vertices[v0].firstarc;w!=NULL;w=w->nextarc) {
		if(!visited[w->adjVex]){
			printf("%d ",G->vertices[w->adjVex].data);
			visited[w->adjVex]=1;
			EnQueue(&Q,w->adjVex);
		}
	}
		
	}
	printf("\n\n");
}
//遍历图 
void TraverseG(ALGragh *G){
	int v;
	//深度优先搜索遍历图的结果 
	printf("\n深度优先搜索遍历图的结果 :");
	for(v=0;v<G->vexnum;v++) visited[v]=0;
	for(v=0;v<G->vexnum;v++)
	    if(!visited[v])
	       DFS(G,v);
	//广度优先 搜索遍历图的结果 
	printf("\n广度优先搜索遍历图的结果 :");
	for(v=0;v<G->vexnum;v++) visited[v]=0;
	for(v=0;v<G->vexnum;v++)
	    if(!visited[v])
	       BFS(G,v);
} 
//用广度遍历计算是否连通
int connect(ALGragh *G) {
	int count=0;
		for(int v=0;v<G->vexnum;v++) visited[v]=0;
	for(int v=0;v<G->vexnum;v++)
	    if(!visited[v]){
	    	DFS(G,v);
	    	count++;
		}
	printf("\n\n");
	return count;
}
 
//------------------------------------------------------------

//展示邻接矩阵存储
void showGragh(AMGragh *G){
	for(int i=0;i<G->vexnum;i++){
		printf("%d",G->vexs[i]);
	}
	printf("\n");
	for(int i=0;i<G->vexnum;i++){
		for(int j=0;j<G->vexnum;j++){
			printf("%d ",G->arc[i][j]);
		}
		printf("\n"); 
	} 
}

 
//LocationVex:确定v1 v2在G中的位置 
int LocationVex(AMGragh *G,int num){
	int i=0;
	for( i=0;i<G->vexnum;i++){
		if(G->vexs[i]==num){ 
		break;
		}
	}
	return i;
}
 //用邻接矩阵创建无向网 
int CreateUDN(AMGragh *G){
	int i=0,j=0;
	printf("请输入总顶点数和总边数:");
	scanf("%d %d",&G->vexnum,&G->arcnum);
	printf("请输入顶点信息:");
	for(i=0;i<G->vexnum;i++){
		scanf("%d",&G->vexs[i]);
	}
	//初始化邻接矩阵
	for(i=0;i<G->vexnum;i++){
		for(j=0;j<G->vexnum;j++){
			G->arc[i][j]=0;   //边的权值全为极大值 
		}
	} 
	//构造邻接矩阵                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
	 int k=0,w;
	 int v1,v2;
	 printf("请输入一条边所依附的顶点及边的权值\n"); 
	 for(k=0;k<G->arcnum;k++){
	 	scanf("%d %d %d",&v1,&v2,&w);
	 	//LocationVex:确定v1 v2在G中的位置 
	 	i=LocationVex(G,v1);
	 	j=LocationVex(G,v2);
	 	G->arc[i][j]=w;              //边<v1,v2>的权值为w 
	 	G->arc[j][i]=G->arc[i][j];    //边<v2,v1>的权值为w 
	 } 
	 return 0;
}




;