有向图的深度优先遍历

#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;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值