#include <stdio.h>
#include <corecrt_malloc.h>
#define MAX 10
//数据
char V[] = { 'a','b','c','d' };
char edges[][2] = { {'a','b'},{'a','d'},{'b','c'},{'b','d'},{'c','d'} };
//定义结构体 三层 一层是邻接表 包含顶点数 边数 顺序表的长度
//二层是顺序表的节点 包含节点内寸的数据 以及第一个指针指向链表的位置
//三层是链表节点 包含一个数据(数据用int 及数据在顺序表中的位置来表示 当顺序表中data较大可以减少内存的使用)一个NEXT指针
//结构体的创建时候要3,2,1要不编译过程出错
typedef struct P3 {
int n;
struct P3* next;
}P3, * PP3;
typedef struct P2 {
char data;
P3* first;
}P2, * PP2;
typedef struct P1 {
int len_edge;//边的个数
int len_v;//顶点个数
P2 SXB[MAX];
}P1, * PP1;
//查找数据在顺序表中位置
int get(PP1 k, char a) {
int i = 0;
for (i; i < k->len_v; i++) {
if (k->SXB[i].data == a) {
return i;
}
}
return -1;
}
//链接链表节点 查找到最后一个链表节点让后在其后面链接新节点 传入的参数都是链表节点指针
void link(PP3 k, PP3 node) {
//先查找链表最后一个节点
PP3 m;
m = k;
while (m->next != NULL) {
m = m->next;
}
m->next = node;
}
//遍历输出邻接表
void pout(PP1 pg) {
//创建一个临时链表指针
PP3 m;
//按照顺序表来遍历 遍历一个点看看是否有链表 有链表就遍历链表没有就下一个顺序表的节点
for (int i = 0; i < pg->len_v; i++) {
printf("%c", pg->SXB[i].data);
printf("\t");
m = pg->SXB[i].first;
while (m != NULL) {
printf("%c", pg->SXB[m->n].data);
m = m->next;
}
printf("\n");
}
return;
}
// 若图之间不是通图不能遍历完全 所以在遍历时要用for循环
//深度优先遍历邻接表 传入邻接表 和要访问元素的顺序表下标 以及visit数组记录元素是否被访问过
//递归思想 从任意一个元素开始 直接将其设为visit=1标明访问 让后通过其链表访问下一个元素
//当接收到下一个元素时先根据visit判断此元素是否被访问过 如果被访问过就继续访问((链表))的下一个元素
//如果没被访问过 那就从顺序表里面找到该元素 并从该元素的链表开始访问 此过程调用了很多堆栈 (每一个链表都会被遍历完)
void dfs(PP1 pg,int n,int visit[]) {
PP3 node;//创建一个临时链表指针
node = pg->SXB[n].first;//让指针指向该元素的链表第一个节点 (之后要遍历整个链表)
visit[n] = 1;
printf("%c", pg->SXB[n].data);
//判断此时指针是否指向空 若为空表明该条链表遍历完毕 但是并不是所有元素遍历完毕 (所以顺序表有几个元素就会创建几个堆栈 每一个边都被遍历了一次时间复杂度与边的数量有关)
while (node !=NULL) {
//判断此时指针所指向元素是否已经遍历若没有遍历 则直接遍历 若已经遍历 则让指针指向链表的下一个元素;
if (visit[node->n] == 0) {
dfs(pg, node->n, visit);
}
node = node->next;
}
}
//有向图的构建
int main() {
//创建一个数组 1表示该元素已经被遍历
int visit[sizeof(V) / sizeof(V[0])];
//把visit数组全部置为0
for (int i = 0; i < sizeof(V) / sizeof(V[0]); i++) {
visit[i] = 0;
}
//创建一个邻接表
PP1 pg;
pg = (PP1)calloc(1, sizeof(P1));//申请邻接表的空间 内存全部设为0
//初始化邻接表的边值和顶点数
pg->len_edge = sizeof(edges) / sizeof(edges[0]); //用sizeof 来计算数组中元素的数量
pg->len_v = sizeof(V) / sizeof(V[0]);
//邻接表的顺序表中填充顶点
for (int i = 0; i < pg->len_v; i++) {
pg->SXB[i].data = V[i];//按照数组V中的顺序依次放入顺序表中
pg->SXB[i].first = NULL; //这里初始时候已经是NULL
}
//邻接表边的填充 先根据边的两个顶点 找到链表节点应该在那个位置 让后插入即可
int j1, k2;//用来接收顶点在顺序表中的位置(下标)
PP3 node1, node2;//用来做临时链表节点
for (int i = 0; i < pg->len_edge; i++) {
//获得边两头数据的位置
j1 = get(pg, edges[i][0]);
k2 = get(pg, edges[i][1]);
//为链表节点申请空间
node1 = (PP3)calloc(1, sizeof(P3));
node2 = (PP3)calloc(1, sizeof(P3));
//初始化链表节点 其NEXT在申请时就设为NULL了 不再设置了
node1->n = j1;
node2->n = k2;
//先给第一个节点后面的链表插入节点 如果链表还没节点直接让FIRST指向节点即可 如果有节点就遍历到最后一个节点在链接
if (pg->SXB[j1].first == NULL) {
pg->SXB[j1].first = node2;
}
else {
link(pg->SXB[j1].first, node2);
}
同理给尾节点链表插入节点 应为是无向图 所以 有A->B 就有 B->A
//if (pg->SXB[k2].first == NULL) {
// pg->SXB[k2].first = node1;
//}
//else {
// link(pg->SXB[k2].first, node1);
//}
}
pout(pg);
for (int i = 0; i < pg->len_v; i++) {
if (visit[i] = 0) {
dfs(pg, 0, visit);
}
}
return 0;
}
有向图的深度优先遍历
最新推荐文章于 2024-04-27 12:39:09 发布