图
首先关于图的一些定义
箭头
<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;
}
邻接表的显示结果为
可以发现存储结果是正确的
对于图的遍历操作
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;
}
如果有什么描述错误的地方欢迎指正。