图的存储与深搜广搜

首先关于图的一些定义

箭头

<v,w>:意思是指箭头由v指向w,其中箭头是v,箭尾是w。如下图所示:

无向图:

两个点之间没有具体指向的图就是无向图。<v,w>==<w,v>。如下图所示:

有向图

两个点之间有具体的箭头指向。<v,w>不等于<w,v>

邻接表:

通常用邻接表来记录图上个节点之间的连接关系

如下图所示:

这个图的意思是:首先用一个表来记录所有顶点的信息(对应蓝色列表),同时表中的每一栏后面都接有一个链表(对应绿色的链表)用来记录这个顶点连接的其他点信息。

给每一个节点分别表上编号(0,1,2,3,4)

然后观察图可以知道节点A连接的节点有B,C,D所以A表中以A头节点的链表就和节点1(B),3(D),2(C)连成一个新链表。其他同理,但是由于这是无向图,所以以A节点位头节点的链表包含有节点D,同时以D节点位头节点的链表也要包含有节点A

矩阵

用矩阵来表示图的信息,每个节点的下标是[x,y],如果[x,y]=1,就说明节点x,y是相连的。否则就是没有相连的关系。

但是矩阵由于有很多的没用信息0,会浪费很多空间,所以如果存储大量信息时通常使用邻接表来存储。
下面是代码演示:
假设图是这样的:

首先书写结构体用于存储图中的一些信息。
typedef struct Enode {
	int ivex;
	struct Enode* next_edge;
}Enode;

typedef struct Vnode {
	char data;
	struct Vnode* first_edge;
};

typedef struct PLgraph {
	int edge_num;
	int node_num;
	Vnode* arr[MAX_SIZE];
};

现在创建邻接表来存储无向图
PLgraph* store_undirected_graph() {
	char vexs[] = { 'A','B','C','D','E','F','G' };
	char edges[][2] = {
		{'A','C'},
		{'A','D'},
		{'A','F'},
		{'B','C'},
		{'C','D'},
		{'E','G'},
		{'F','G'}
	};

    //记录顶点个数
	int len1 = (sizeof(vexs) / sizeof(vexs[0]));
    //记录弧的条数
	int len2 = (sizeof(edges) / sizeof(edges[0]));
	
    //记录箭头点的信息
	char c1;
    //记录箭尾点的信息
	char c2;

    //记录箭头点的存储位置
	int p1;
    //记录箭尾点的位置
	int p2;

    //箭头顶点
	Enode* node1;
    //箭尾顶点
	Enode* node2;

	PLgraph* G = (PLgraph*)calloc(1, sizeof(PLgraph));

	//初始化邻接表中个顶点信息
	for (int i = 0; i < len1; i++) {
		G->arr[i]->data = vexs[i];
		G->arr[i]->first_edge = NULL;
	}

	//初始化链表节点之间的关系
	for (int i = 0; i < len2; i++) {
		c1 = edges[i][0];
		c2 = edges[i][1];

		p1 = find_position(c1, G, len1);
		p2 = find_position(c2, G, len1);

		node1 = (Enode*)calloc(1, sizeof(Enode));
		node1->ivex = p1;

		node2 = (Enode*)calloc(1, sizeof(Enode));
		node2->ivex = p2;

		if (G->arr[p1]->first_edge == NULL) {
			G->arr[p1]->first_edge = node2;
		}
		else {
			link_last(G->arr[p1]->first_edge, node2);
		}
		
		if (G->arr[p2]->first_edge == NULL) {
			G->arr[p2]->first_edge = node1;
		}
		else {
			link_last(G->arr[p2]->first_edge, node1);
		}
	}
    //返回存储好了的邻接表
	return G;
}
邻接表的显示结果为

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-usL8y51d-1648309976644)(图.assets/image-20220326000228231.png)]

可以发现存储结果是正确的

对于图的遍历操作
DFS

也就是对应二叉树的后序遍历操作

代码演示

void DFS(int* visit, PLgraph* G, int i) {
	if (visit[i])return;
	visit[i] = 1;

	Enode* node = G->arr[i]->first_edge;
	printf("%c ", G->arr[i]->data);
	while (node) {
		if (!visit[node->ivex])
			DFS(visit, G, node->ivex);
		node = node->next_edge;
	}
	return ;
}

void DFS_traverse(PLgraph* G) {
	int visit[MAX_SIZE] = {};
	printf("DFS:\n");
	for (int i = 0; i < G->node_num; i++) {
		DFS(visit, G, i);
	}
	printf("\n");
	return;
}
BFS:广搜(对应二叉树的层序遍历)
代码演示
void BFS(PLgraph* G) {
	int visit[MAX_SIZE] = {};
	int queue[MAX_SIZE] = {};
	int head = 0;
	int tail = 0;

	printf("BFS\n");
	for (int i = 0; i < G->node_num; i++) {
		if (visit[i] == 0) {
			printf("%c ", G->arr[i]->data);
			queue[tail++] = i;
			visit[i] = 1;
		}
		while (head != tail) {
			Enode* node = G->arr[queue[head++]]->first_edge;
			while (node) {
				if (visit[node->ivex] != 1) {
					visit[node->ivex] = 1;
					queue[tail++] = node->ivex;
					printf("%c ", G->arr[node->ivex]->data);
				}
				node = node->next_edge;
			}
		}
	}
	return;
}

最终结果

在这里插入图片描述

有向图

有向图的代码很简单,就是把无向图那个相互连接的代码改写成单向连接即可。

PLgraph* store_directed_graph() {
	char vexs[] = { 'A','B','C','D','E','F','G' };
	char edges[][2] = {
		{'A','C'},
		{'A','D'},
		{'A','F'},
		{'B','C'},
		{'C','D'},
		{'E','G'},
		{'F','G'}
	};

	char c1;
	char c2;

	int p1;
	int p2;

	PLgraph* G = (PLgraph*)calloc(1, sizeof(PLgraph));
	G->edge_num = sizeof(edges) / sizeof(edges[0]);
	G->node_num = sizeof(vexs) / sizeof(vexs[0]);

	for (int i = 0; i < G->node_num; i++) {
		G->arr[i] = (Vnode*)calloc(1, sizeof(Vnode));
		G->arr[i]->data = vexs[i];
	}

	for (int i = 0; i < G->edge_num; i++) {
		c1 = edges[i][0];
		c2 = edges[i][1];

		p1 = find_position(c1, G, G->node_num);
		p2 = find_position(c2, G, G->node_num);

		Enode* node1 = (Enode*)calloc(1, sizeof(Enode));
		node1->ivex = p2;

		if (G->arr[p1]->first_edge == NULL) {
			G->arr[p1]->first_edge = node1;
		}
		else {
			link_last(G->arr[p1]->first_edge, node1);
		}
	}
	return G;
}
邻接表的存储结果

总的代码如下图所示
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define MAX_SIZE 40

typedef struct Enode {
	int ivex;
	struct Enode* next_edge;
}Enode;

typedef struct Vnode {
	int data;
	struct Enode* first_edge;
};

typedef struct PLgraph {
	int edge_num;
	int node_num;
	Vnode* arr[MAX_SIZE];
};

int find_position(char ch, PLgraph* G,int len) {
	for (int i = 0; i < len; i++) {
		if (ch == G->arr[i]->data) {
			return i;
		}
	}
	return -1;
}

//将节点连接到链表尾
void link_last(Enode* head, Enode* node) {
	while (head->next_edge) {
		head = head->next_edge;
	}
	head->next_edge = node;
	return;
}

PLgraph* store_undirected_graph() {
	char vexs[] = { 'A','B','C','D','E','F','G' };
	char edges[][2] = {
		{'A','C'},
		{'A','D'},
		{'A','F'},
		{'B','C'},
		{'C','D'},
		{'E','G'},
		{'F','G'}
	};

	int len1 = (sizeof(vexs) / sizeof(vexs[0]));
	int len2 = (sizeof(edges) / sizeof(edges[0]));

	char c1;
	char c2;

	int p1;
	int p2;

	Enode* node1;
	Enode* node2;

	PLgraph* G = (PLgraph*)calloc(1, sizeof(PLgraph));
	G->edge_num = len2;
	G->node_num = len1;

	//初始化邻接表中个顶点信息
	for (int i = 0; i < len1; i++) {
		G->arr[i] = (Vnode*)calloc(1, sizeof(Vnode));
		G->arr[i]->data = vexs[i];
		G->arr[i]->first_edge = NULL;
	}

	//初始化链表节点之间的关系
	for (int i = 0; i < len2; i++) {
		c1 = edges[i][0];
		c2 = edges[i][1];

		p1 = find_position(c1, G, len1);
		p2 = find_position(c2, G, len1);

		node1 = (Enode*)calloc(1, sizeof(Enode));
		node1->ivex = p1;

		node2 = (Enode*)calloc(1, sizeof(Enode));
		node2->ivex = p2;

		if (G->arr[p1]->first_edge == NULL) {
			G->arr[p1]->first_edge = node2;
		}
		else {
			link_last(G->arr[p1]->first_edge, node2);
		}
		
		if (G->arr[p2]->first_edge == NULL) {
			G->arr[p2]->first_edge = node1;
		}
		else {
			link_last(G->arr[p2]->first_edge, node1);
		}
	}
	return G;
}

PLgraph* store_directed_graph() {
	char vexs[] = { 'A','B','C','D','E','F','G' };
	char edges[][2] = {
		{'A','C'},
		{'A','D'},
		{'A','F'},
		{'B','C'},
		{'C','D'},
		{'E','G'},
		{'F','G'}
	};

	char c1;
	char c2;

	int p1;
	int p2;

	PLgraph* G = (PLgraph*)calloc(1, sizeof(PLgraph));
	G->edge_num = sizeof(edges) / sizeof(edges[0]);
	G->node_num = sizeof(vexs) / sizeof(vexs[0]);

	for (int i = 0; i < G->node_num; i++) {
		G->arr[i] = (Vnode*)calloc(1, sizeof(Vnode));
		G->arr[i]->data = vexs[i];
	}

	for (int i = 0; i < G->edge_num; i++) {
		c1 = edges[i][0];
		c2 = edges[i][1];

		p1 = find_position(c1, G, G->node_num);
		p2 = find_position(c2, G, G->node_num);

		Enode* node1 = (Enode*)calloc(1, sizeof(Enode));
		node1->ivex = p2;

		if (G->arr[p1]->first_edge == NULL) {
			G->arr[p1]->first_edge = node1;
		}
		else {
			link_last(G->arr[p1]->first_edge, node1);
		}
	}
	return G;
}


void DFS(int* visit, PLgraph* G, int i) {
	if (visit[i])return;
	visit[i] = 1;

	Enode* node = G->arr[i]->first_edge;
	printf("%c ", G->arr[i]->data);
	while (node) {
		if (!visit[node->ivex])
			DFS(visit, G, node->ivex);
		node = node->next_edge;
	}
	return ;
}

void DFS_traverse(PLgraph* G) {
	int visit[MAX_SIZE] = {};
	printf("DFS:\n");
	for (int i = 0; i < G->node_num; i++) {
		DFS(visit, G, i);
	}
	printf("\n");
	return;
}

void BFS(PLgraph* G) {
	int visit[MAX_SIZE] = {};
	int queue[MAX_SIZE] = {};
	int head = 0;
	int tail = 0;

	printf("BFS\n");
	for (int i = 0; i < G->node_num; i++) {
		if (visit[i] == 0) {
			printf("%c ", G->arr[i]->data);
			queue[tail++] = i;
			visit[i] = 1;
		}
		while (head != tail) {
			Enode* node = G->arr[queue[head++]]->first_edge;
			while (node) {
				if (visit[node->ivex] != 1) {
					visit[node->ivex] = 1;
					queue[tail++] = node->ivex;
					printf("%c ", G->arr[node->ivex]->data);
				}
				node = node->next_edge;
			}
		}
	}
	return;
}

void print_graph(PLgraph* G) {
	int len = G->node_num;
	for (int i = 0; i < len; i++) {
		Enode* head = G->arr[i]->first_edge;
		printf("%c(%d) ", G->arr[i]->data, i);
		while (head) {
			printf("%c(%d)", G->arr[head->ivex]->data, head->ivex);
			head = head->next_edge;
		}
		printf("\n");
	}
	return;
}

int main() {
	PLgraph* G = NULL;
	//G = store_undirected_graph();
	G = store_directed_graph();
	print_graph(G);
	DFS_traverse(G);
	BFS(G);
	return 0;
}


如果有什么描述错误的地方欢迎指正。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值