c语言编程 输出一个无向图的邻接表,邻接矩阵,进行深度和广度优先遍历

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

//#define GRAPH_LIST		

int *g_visited;  //访问标志
int *g_queue;  //定义一个队列Q
int g_front=-1,g_rear=-1;         //初始化队列Q
int g_queue_size;
int g_vernum;
int g_arcnum;

typedef struct VNode    //头结点的类型定义
{
	char  data[20];   //用于存储的顶点
	int nextver_index;       //边指向的顶点的位置
	struct VNode *nextver_point;   //指示下一个与该顶点相邻接的顶点
}AdjList;
typedef struct            //图的类型定义
{
      AdjList *vertex;  //用于存储顶点
      int *arcs;                //邻接矩阵,存储边的信息
      int vernum,arcnum;             //顶点数和边的数目
}MGraph;

void Visited_init(MGraph *N)
{
	int v;
	for(v=0;v<g_vernum;v++)
	{
		g_visited[v]=0;   //访问标志数组初始化为未被访问
	}
	return;
}

void CreateGraph_L(MGraph *N)   //邻接表表示
{
   int i,j,k;
   
   AdjList *p;
   
   printf("请输入%d个顶点的值:\n",g_vernum);  
   for(i=0;i<g_vernum;i++)    //将顶点存储在头结点中
	{
		printf("%d vlaue:\t",i);
		scanf("%s",N->vertex[i].data);
		N->vertex[i].nextver_point=&N->vertex[i];  //将相关联的顶点置为空
		N->vertex[i].nextver_index = 0;
   }
	printf("\n");

   for(k=0;k<g_arcnum;)   
   {
		printf("第 %d 条边的两个顶点序号(逗号隔开):\t",k+1);
   
        scanf("%d,%d",&i,&j);
		if(i >=g_vernum || j>=g_vernum)
		{
			printf("第 %d 条边的两个顶点序号(逗号隔开): 输入错误,请重新输入\t\n\n",k+1);
			continue;
		}
		//建立邻接表关系链
        p=(AdjList *)malloc(sizeof(AdjList));
        p->nextver_index=j;
        p->nextver_point=N->vertex[i].nextver_point;
        N->vertex[i].nextver_point=p;
        p=(AdjList *)malloc(sizeof(AdjList));
        p->nextver_index=i;
        p->nextver_point=N->vertex[j].nextver_point;
        N->vertex[j].nextver_point=p;
		k++;
  }
}
void DisplayGraph_L(MGraph *N)   //图的邻接表存储结构输出
{
	int i;
	AdjList *p;
	printf("邻接表表示为:\n");
 	for(i=0;i<g_vernum;i++)
	{
		printf("%s[%d]",N->vertex[i].data,i);
		p=N->vertex[i].nextver_point;   //将p指向边表的第一个结点
		while(p != &N->vertex[i])
		{
			printf("->%s[%d] ",N->vertex[p->nextver_index].data,p->nextver_index);
			p=p->nextver_point;
		}
		printf("\n");
   }
}
void CreateGraph_T(MGraph *N)    //邻接矩阵表示
{   
	int i,j,k;

	//初始化邻接矩阵边的信息初始化为空
	memset((char *)N->arcs, 0, 4*g_vernum * g_vernum);
	
	printf("请输入%d个顶点的值:\n",g_vernum);  
	for(i=0;i<g_vernum;i++) 
	{
		printf("%d vlaue:\t",i);
		scanf("%s",N->vertex[i].data);
	}
	
	for(k=0;k<g_arcnum;)
	{
		printf("第 %d 条边的两个顶点序号(逗号隔开):\t",k+1);
        scanf("%d,%d",&i,&j);
		if(i >=g_vernum|| j>=g_vernum)
		{
			printf("第 %d 条边的两个顶点序号(逗号隔开): 输入错误,请重新输入\t\n\n",k+1);
			continue;
		}
		N->arcs[i*g_vernum + j]=1;
		N->arcs[j*g_vernum + i]=1;
		k++;
	}

}

void DisplayGraph_T(MGraph *N)        //输出邻接矩阵存储表示的图N 
{
   int i,j;
   printf("\n无向图的邻接矩阵:\n");
   for(i=0;i<g_vernum;i++)
   {
		printf("%s\t",N->vertex[i].data);
   }
	printf("\n");

   for(i=0;i<g_vernum;i++)
   {
		for(j=0;j<g_vernum;j++)
		{
			printf("%8d",N->arcs[i*g_vernum + j]);
		}
		printf("\n");
	}
}

void Visit(char *v)   //访问函数,输出图中的顶点
{
	 printf("%s -> ",v);
}
int Visited_set(int key)
{
	g_visited[key]=1;    //设置访问标志为1,表示已经被访问过
	return 0;
}
int Visited_get(int key)
{
	return g_visited[key];
}
int Enqueue(int key)
{
	g_rear++;
	g_queue[g_rear % g_queue_size] = key;    //v入队列 g_rear进队口
	return 0;
}
int Dequeue(void)
{
	g_front++; 
	return g_queue[g_front%g_queue_size];   //队首元素出队赋值给v
}
int Queue_empty()
{
	return g_front == g_rear;
}
int Queue_full()
{
	return (g_rear - g_front) == g_queue_size;
}
void Queue_init()
{
	g_front=-1;
	g_rear=-1;         //初始化队列Q
}



void DFS_L(MGraph *N, AdjList *cur, int i)   //从顶点r出发递归深度优先搜索图N
{
	AdjList *tmp = NULL;
	Visited_set(i);
	Visit(N->vertex[i].data);  //访问第r个顶点

	while(&N->vertex[i] != cur)
	{
		if(Visited_get(cur->nextver_index)!=1)
		{
			tmp = N->vertex[cur->nextver_index].nextver_point;
			DFS_L(N, tmp, cur->nextver_index);
		}
		cur = cur->nextver_point;
	}
	return;
}

void DFSTraverse_L(MGraph *N)  // 从第一个顶点起,深度优先搜索图N 
{
	int v;
	printf("图N的深度优先遍历:\n");
	Visited_init(N);
	
	for(v=0; v<g_vernum; v++)
	{
		if(Visited_get(v) == 1)
		{
			continue;
		}

		DFS_L(N, N->vertex[v].nextver_point, v);   //对未访问的顶点r进行深度优先遍历
	}

	printf(":end\n");
}
void DFS_T(MGraph *N,int i)   //从顶点r出发递归深度优先搜索图N
{
	int j;
	Visited_set(i);
	Visit(N->vertex[i].data);  //访问第r个顶点

	for(j=0;j<g_vernum;j++)
	{
		if(N->arcs[i*g_vernum + j] != 0 && Visited_get(j)!=1)
		{
			DFS_T(N,j);
		}
	}
	return;
}
void DFSTraverse_T(MGraph *N)  // 从第一个顶点起,深度优先搜索图N 
{
	int v;
	printf("图N的深度优先遍历:\n");

	Visited_init(N);
	
	for(v=0; v<g_vernum; v++)
	{
		if(Visited_get(v) == 1)
		{
			continue;
		}

		DFS_T(N,v);   //对未访问的顶点r进行深度优先遍历
	}
	printf(":end\n");
}
int	BFS_L(MGraph *N)
{
	int t=0;
	AdjList *p;
	while(!Queue_empty() && !Queue_full())  //如果队列不空
	{
		t=Dequeue();   //队首元素出队赋值给v

		p=N->vertex[t].nextver_point;

		while(p!=&N->vertex[t])  //遍历序号为v的所有邻接点
		{
			if(Visited_get(p->nextver_index)==0)  //如果该顶点未被访问过
			{
				Visited_set(p->nextver_index);
				Visit(N->vertex[p->nextver_index].data);
				Enqueue(p->nextver_index);
			}
			p=p->nextver_point;   //p指向下一个邻接点
		}
	}
	return 0;
}

void BFSTraverse_L(MGraph *N)  //从第一个顶点出发,按广度优先非递归搜索图N
{
	int v;

	printf("按广度优先非递归搜索图N: \n");
	Visited_init(N);
	Queue_init();

	for(v=0; v<g_vernum; v++)
	{/*防止出现了图*/
		if(Visited_get(v) == 1)
		{
			continue;
		}
		Visited_set(v);

		Visit(N->vertex[v].data);
		Enqueue(v);
		BFS_L(N);
	}
	printf(":end \n");
}
int BFS_T(MGraph *N)
{
	int j;
	int t=0;
	while(!Queue_empty() && !Queue_full())  //如果队列不空
	{
		t=Dequeue();   //队首元素出队赋值给v
		for(j=1;j<g_vernum;j++)
		{
			if(N->arcs[t*g_vernum + j]==1)
			{
				if(Visited_get(j)==0)  //如果该顶点未被访问过
				{
					Visited_set(j);
					Visit(N->vertex[j].data);
					Enqueue(j);
				}
			}
		}
		
	}
}
void BFSTraverse_T(MGraph *N)  //从第一个顶点出发,按广度优先非递归搜索图N
{
	
	int v;

  	printf("图N的广度优先遍历:\n");
	Visited_init(N);
	Queue_init();

	for(v=0; v<g_vernum; v++)
	{
		if(Visited_get(v) == 1)
		{
			continue;
		}
		Visited_set(v);

		Visit(N->vertex[v].data);
		Enqueue(v);
		BFS_T(N);
	}

	printf(":end \n");

}
int GraphInit(MGraph *N)
{
	g_queue_size = g_vernum * g_vernum;
	/*初始化邻接表*/
	N->vertex = (AdjList *)malloc(sizeof(AdjList) * g_vernum);
	/*初始化邻接矩阵*/
	N->arcs = (int *)malloc(sizeof(int) * g_vernum * g_vernum);
	/*初始化访问标志*/
	g_visited = (int *)malloc(sizeof(int) * g_vernum);
	/*初始化队列*/
	g_queue = (int *)malloc(sizeof(int) * g_queue_size);

		
	if(N->vertex == NULL || N->arcs == NULL 
		|| g_visited == NULL || g_queue == NULL)
	{
		return -1;
	}
		
	return 0;
}
int GraphRelease(MGraph *N)
{

#ifdef GRAPH_LIST
	int i;
 	AdjList *p;
	AdjList *t;
	for(i=0;i<g_vernum;i++)
	{
		printf("%s[%d]",N->vertex[i].data,i);
		p=N->vertex[i].nextver_point;   //将p指向边表的第一个结点
		while(p != &N->vertex[i])
		{
			t=p;
			p=p->nextver_point;
			free(t);
		}
	}
#endif
	free(N->arcs);
	free(g_visited);
	free(g_queue);
	free(N->vertex);
	return 0;
	
}
int  main()
{
	int ret;
	MGraph N;

again:
	printf("请输入无向图的顶点数,边数(逗号隔开):\t");
	scanf("%d,%d",&g_vernum,&g_arcnum);
	printf("\n\n");
	if( g_vernum== 0 || g_arcnum== 0)
	{
		goto again;
	}

	ret = GraphInit(&N);
	if(ret == -1)
	{
		printf("程序初始化失败\n");
		return 0;
	}
#ifdef GRAPH_LIST
	printf("邻接表链表结构\n");
	CreateGraph_L(&N);
	DisplayGraph_L(&N);
	BFSTraverse_L(&N);
	DFSTraverse_L(&N);

#endif
	printf("\n\n邻接矩阵结构\n");
	CreateGraph_T(&N);
	DisplayGraph_T(&N);
	BFSTraverse_T(&N);
	DFSTraverse_T(&N);
	
	GraphRelease(&N);
	exit(0);
	return 0;
 }

### 回答1: 邻接表邻接矩阵的两种常见表示方法。下面分别给出邻接表邻接矩阵实现的广度遍历和深度遍历的代码。 ### 邻接表 ```c #include <stdio.h> #include <stdlib.h> #define MAX_VERTEX_NUM 100 // 中最大顶点数 // 邻接表中表示边的结构体 typedef struct EdgeNode { int adjvex; // 邻接点在数组中的位置下标 struct EdgeNode *next; // 指向下一个邻接点的指针 } EdgeNode; // 邻接表中表示顶点的结构体 typedef struct VertexNode { int data; // 顶点的数据 EdgeNode *firstedge; // 指向第一个邻接点的指针 } VertexNode, AdjList[MAX_VERTEX_NUM]; // 定义结构体 typedef struct Graph { AdjList adjList; // 邻接表 int vexnum, arcnum; // 顶点数和边数 } Graph; // 初始化邻接表 void InitGraph(Graph *G) { G->vexnum = G->arcnum = 0; for (int i = 0; i < MAX_VERTEX_NUM; i++) { G->adjList[i].data = 0; G->adjList[i].firstedge = NULL; } } // 添加边 void AddEdge(Graph *G, int u, int v) { EdgeNode *p = (EdgeNode *)malloc(sizeof(EdgeNode)); p->adjvex = v; p->next = G->adjList[u].firstedge; G->adjList[u].firstedge = p; } // 创建 void CreateGraph(Graph *G) { printf("请输入顶点数和边数:"); scanf("%d %d", &G->vexnum, &G->arcnum); printf("请输入每个顶点的数据:"); for (int i = 0; i < G->vexnum; i++) { scanf("%d", &G->adjList[i].data); } printf("请输入每条边的起点和终点:"); for (int i = 0; i < G->arcnum; i++) { int u, v; scanf("%d %d", &u, &v); AddEdge(G, u, v); AddEdge(G, v, u); // 无向图需要加上反向边 } } // 访问顶点 void Visit(int v) { printf("%d ", v); } // 广度遍历 void BFS(Graph *G, int v) { int visited[MAX_VERTEX_NUM] = {0}; // 标记是否被访问过 int queue[MAX_VERTEX_NUM], front = 0, rear = 0; // 队列 Visit(v); visited[v] = 1; queue[rear++] = v; while (front != rear) { int u = queue[front++]; for (EdgeNode *p = G->adjList[u].firstedge; p != NULL; p = p->next) { int w = p->adjvex; if (!visited[w]) { Visit(w); visited[w] = 1; queue[rear++] = w; } } } } // 深度遍历 void DFS(Graph *G, int v, int visited[]) { Visit(v); visited[v] = 1; for (EdgeNode *p = G->adjList[v].firstedge; p != NULL; p = p->next) { int w = p->adjvex; if (!visited[w]) { DFS(G, w, visited); } } } int main() { Graph G; InitGraph(&G); CreateGraph(&G); printf("广度遍历:"); BFS(&G, 0); printf("\n深度遍历:"); int visited[MAX_VERTEX_NUM] = {0}; DFS(&G, 0, visited); return 0; } ``` ### 邻接矩阵 ```c #include <stdio.h> #include <stdlib.h> #define MAX_VERTEX_NUM 100 // 中最大顶点数 // 定义结构体 typedef struct Graph { int vexnum, arcnum; // 顶点数和边数 int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; // 邻接矩阵 } Graph; // 初始化邻接矩阵 void InitGraph(Graph *G) { G->vexnum = G->arcnum = 0; for (int i = 0; i < MAX_VERTEX_NUM; i++) { for (int j = 0; j < MAX_VERTEX_NUM; j++) { G->arcs[i][j] = 0; } } } // 添加边 void AddEdge(Graph *G, int u, int v) { G->arcs[u][v] = 1; G->arcs[v][u] = 1; // 无向图需要加上反向边 } // 创建 void CreateGraph(Graph *G) { printf("请输入顶点数和边数:"); scanf("%d %d", &G->vexnum, &G->arcnum); printf("请输入每个顶点的数据:"); for (int i = 0; i < G->vexnum; i++) { for (int j = 0; j < G->vexnum; j++) { G->arcs[i][j] = 0; } scanf("%*d"); } printf("请输入每条边的起点和终点:"); for (int i = 0; i < G->arcnum; i++) { int u, v; scanf("%d %d", &u, &v); AddEdge(G, u, v); } } // 访问顶点 void Visit(int v) { printf("%d ", v); } // 广度遍历 void BFS(Graph *G, int v) { int visited[MAX_VERTEX_NUM] = {0}; // 标记是否被访问过 int queue[MAX_VERTEX_NUM], front = 0, rear = 0; // 队列 Visit(v); visited[v] = 1; queue[rear++] = v; while (front != rear) { int u = queue[front++]; for (int w = 0; w < G->vexnum; w++) { if (G->arcs[u][w] && !visited[w]) { Visit(w); visited[w] = 1; queue[rear++] = w; } } } } // 深度遍历 void DFS(Graph *G, int v, int visited[]) { Visit(v); visited[v] = 1; for (int w = 0; w < G->vexnum; w++) { if (G->arcs[v][w] && !visited[w]) { DFS(G, w, visited); } } } int main() { Graph G; InitGraph(&G); CreateGraph(&G); printf("广度遍历:"); BFS(&G, 0); printf("\n深度遍历:"); int visited[MAX_VERTEX_NUM] = {0}; DFS(&G, 0, visited); return 0; } ``` ### 回答2: 的广度遍历和深度遍历是的两种主要遍历方式。C语言编程中,我们可以用邻接表邻接矩阵实现这两种遍历。 邻接表是一种常见的的表示方法,它通过链表来表示中的每个顶点以及与其相邻的顶点。广度遍历使用队列实现深度遍历使用递归实现邻接矩阵是另一种常见的的表示方法,它使用二维数组来表示的连接情况。广度遍历使用队列实现深度遍历使用栈或递归实现。 对于广度遍历的实现,我们可以按照以下步骤进行: 1. 创建一个队列,并将起始顶点放入队列中。 2. 初始化一个数组visited,用来标记顶点是否被访问过,初始值为0(未访问)。 3. 当队列非空时,执行以下操作: 3.1 出队一个顶点v,并将其标记为已访问。 3.2 访问顶点v,并进行相关操作。 3.3 将v的所有未访问的邻居顶点入队。 对于深度遍历的实现,我们可以按照以下步骤进行: 1. 创建一个栈,并将起始顶点放入栈中。 2. 初始化一个数组visited,用来标记顶点是否被访问过,初始值为0(未访问)。 3. 当栈非空时,执行以下操作: 3.1 出栈一个顶点v,并将其标记为已访问。 3.2 访问顶点v,并进行相关操作。 3.3 将v的所有未访问的邻居顶点入栈。 以上是用邻接表邻接矩阵实现的广度遍历和深度遍历的基本思路。具体实现时,我们需要根据具体的数据结构来实现相应的操作,比如针对邻接表的创建、节点插入等操作,以及邻接矩阵的创建、二维数组的遍历等操作。 ### 回答3: 邻接表邻接矩阵是常用的存储结构。它们可以用于实现广度优先遍历(BFS)和深度优先遍历(DFS)算法。 邻接表是由中每个顶点的所有邻接顶点构成的链表。对于无向图邻接表一个无序链表;对于有向邻接表一个有序链表。我们可以使用一个数组来表示邻接表,数组的每个位置存储一个链表,链表的节点表示邻接顶点。 邻接矩阵一个二维数组,行列分别表示中的顶点,矩阵中的元素表示两个顶点之间是否有边。如果有边,则为1或表示边的权重;如果没有边,则为0。邻接矩阵可以使用二维数组来表示。 对于广度优先遍历算法,我们可以使用一个队列来辅助进行遍历。首先将起始节点放入队列中,然后循环以下步骤:从队列中取出一个节点,遍历该节点的邻接顶点,并将未访问的邻接顶点依次放入队列中。直到队列为空为止。 对于深度优先遍历算法,我们可以使用递归或者栈来辅助进行遍历。首先将起始节点标记为已访问,然后循环以下步骤:选择一个未访问的邻接顶点,递归地对该顶点进行深度优先遍历。直到所有的顶点都被访问为止。 使用邻接表邻接矩阵实现的广度遍历和深度遍历,核心思想是遍历中的每个顶点,并按照特定的算法顺序访问和处理顶点。具体实现细节可以根据具体需求和数据结构选择适合的方式。 总之,使用邻接表邻接矩阵可以很方便地实现的广度遍历和深度遍历,这两种方法适用于不同的场景和需求,可以根据具体情况进行选择和实现
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Brickie-liu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值