VOL.1 图的创建与遍历
发布日期:2022-02-28 07:22:52
浏览次数:31
分类:技术文章
本文共 5458 字,大约阅读时间需要 18 分钟。
图的创建与遍历
1.选择一种存储结构实现有向图的创建
首先,采用邻接矩阵创建图,由于不需要考虑权值问题,因此在邻接矩阵中,0表示没有边,1表示有边,通过两层循环从矩阵转为邻接表的存储结构。邻接表中有两种节点类型,顶点节点按照序号顺序存储在一个数组中,包含序号域和边节点域两个属性,而边节点以相应顶点节点作为头节点构成链式结构,每一个边节点包含序号域、边节点域与顶点节点域(指向与之序号相同的顶点节点方面后续的遍历操作)。
在实际操作中,利用数组存储顶点节点总会出现内存访问冲突的问题,所以改用了链结构存储顶点节点。
//邻接矩阵int adjacency_matrix[size][size] = { { 0, 1, 1, 1, 0, 0, 0}, { 0, 0, 1, 0, 1, 0, 0}, { 0, 0, 0, 0, 1, 1, 0}, { 0, 0, 1, 0, 0, 1, 0}, { 0, 0, 0, 0, 0, 0, 1}, { 0, 0, 0, 0, 1, 0, 1}, { 0, 0, 0, 0, 0, 0, 0}};//顶点节点typedef struct vertexNode { int order; int flag; struct edgeNode* next_edge = NULL; struct vertexNode* next_vertex = NULL;}vertexNode;//顶点节点初始化vertexNode* vertex_node_initialize() { vertexNode* vertex_node = (vertexNode*)malloc(sizeof(vertexNode)); vertex_node->next_edge = NULL; vertex_node->next_vertex = NULL; return vertex_node;}//边节点typedef struct edgeNode { int order; struct edgeNode* next_edge; struct vertexNode* vertex_node;}edgeNode;//边节点初始化edgeNode* edge_node_initialize() { edgeNode* edge_node = (edgeNode*)malloc(sizeof(edgeNode)); edge_node->next_edge = NULL; edge_node->vertex_node = NULL; return edge_node;}//图的邻接表创建vertexNode* create_graph() { vertexNode* vertex_head = vertex_node_initialize(); vertex_head->order = -1; vertexNode* vertex_ptr = vertex_head; for (int i = 0; i < size; i++) { vertexNode* vertex_node = vertex_node_initialize(); vertex_ptr->next_vertex = vertex_node; vertex_ptr = vertex_node; vertex_node->order = i; vertex_node->flag = 0; } vertexNode* vertex_node = vertex_head; for (int row = 0; row < size; row++) { vertex_node = vertex_node->next_vertex; edgeNode* edge_head = edge_node_initialize(); edge_head->order = -1; vertex_node->next_edge = edge_head; edgeNode* edge_ptr = edge_head; for (int column = 0; column < size; column++) { if (adjacency_matrix[row][column] > 0) { edgeNode* edge_node = edge_node_initialize(); edge_ptr->next_edge = edge_node; edge_ptr = edge_ptr->next_edge; edge_node->order = column; edge_node->vertex_node = find_node(vertex_head, column); } } } return vertex_head;}//寻找顶点节点vertexNode* find_node(vertexNode* vertex_head, int order) { vertexNode* p = vertex_head->next_vertex; while (1) { if (p->order == order) return p; else p = p->next_vertex; }}
2. 利用队列实现从序号最小的点开始,对图进行广度优先遍历,将遍历结果输出在屏幕上
访问第一个顶点节点并将该顶点连通的所有顶点节点加入队列。这里是通过每一个顶点的边节点域来确定顶点之间的连通性,又因为在之前建立了边节点与对应顶点节点的连接关系,因此可以直接可以通过边节点域访问对应顶点节点然后将顶点节点加入到队列中。然后依次出队访问出队顶点节点并做同样的操作,直到栈为空。另外由于这是一个连通图,所以不需要考虑对顶点节点依次作为起始点遍历。
//广度优先遍历void breadth_first_traversal(vertexNode* vertex_head, void(*fun)(vertexNode*)) { queue* queues = queue_initialize(); if (vertex_head->next_vertex != NULL) enter_queue(queues, vertex_head->next_vertex); while (queues->front != queues->rear) { vertexNode* vertex_node = delete_queue(queues); visit(vertex_node); edgeNode* edge_node = vertex_node->next_edge->next_edge; while (edge_node != NULL) { if (edge_node->vertex_node->flag == 0) enter_queue(queues, edge_node->vertex_node); edge_node = edge_node->next_edge; } }}//访问打印节点void visit(vertexNode* vertex_node) { if (vertex_node->flag != 1) printf("%d", vertex_node->order); vertex_node->flag = 1;}
3.从序号最小的点开始,用递归算法实现图的深度优先搜索遍历,将遍历结果输出在屏幕上
采用递归的思想,访问起始顶点节点并对与顶点节点连通的顶点节点做深度优先遍历。
//寻找顶点节点void deepth_first_traversal(vertexNode* vertex_node, void(*fun)(vertexNode*)) { fun(vertex_node); edgeNode* edge_node = vertex_node->next_edge; while (edge_node->next_edge != NULL) { edge_node = edge_node->next_edge; deepth_first_traversal(edge_node->vertex_node, visit); }}
4.判断图中任意两点是否有路径,如果有路径,将路径输出在屏幕上。
不需要考虑最短路径问题,所以对起点进行深度优先遍历。在这里使用的是非递归的深度优先遍历,用栈结构存储带访问的深度优先遍历节点,并将路径点存储在另外一个栈结构中,当找到终点后,对存储路径点的栈结构进行倒序输出。
//定义栈结构typedef struct stack { int top; vertexNode* vertexs[2 * size];}stack;//栈的初始化stack* stack_initialize() { stack* stacks = (stack*)malloc(sizeof(stack)); stacks->top = -1; return stacks;}//进栈void push(stack* stacks, vertexNode* vertex_node) { stacks->top++; stacks->vertexs[stacks->top] = vertex_node;}//出栈vertexNode* pop(stack* stacks) { vertexNode* vertex_node = stacks->vertexs[stacks->top]; stacks->top--; return vertex_node;}//路径打印void path_print(stack* stacks, int start, int end) { if (stacks->top == -1) printf("起点%d到终点%d无路径", start, end); else { printf("\n起点%d到终点%d存在路径:", start, end); for (int i = 0; i <= stacks->top; i++) printf("%d", stacks->vertexs[i]->order); }}//路径查找void find_path(vertexNode* vertex_head, int start, int end) { vertexNode* vertex_ptr = vertex_head->next_vertex, * vertex_start = NULL, * vertex_end; while (vertex_ptr != NULL) { if (vertex_ptr->order == start) vertex_start = vertex_ptr; else if (vertex_ptr->order == end) vertex_end = vertex_ptr; vertex_ptr = vertex_ptr->next_vertex; } stack* path_stack = stack_initialize(); stack* find_stack = stack_initialize(); if (vertex_start) push(find_stack, vertex_start); while (find_stack->top != -1) { vertexNode* vertex_node = pop(find_stack); push(path_stack, vertex_node); edgeNode* edge_node = vertex_node->next_edge->next_edge; while (edge_node != NULL) { push(find_stack, edge_node->vertex_node); if (edge_node->order == end) { if (vertex_node->order == 0) push(path_stack, edge_node->vertex_node); path_print(path_stack, start, end); return; } edge_node = edge_node->next_edge; } }}
最终效果
问题分析:在编写的过程中,由于没有对边节点和顶点节点进行初始化,多次出现内存访问冲突等问题,在使用结构体时,必须先进行内存空间的分配与结构体变量的初始化,指针类型可以先置为NULL。
转载地址:https://blog.csdn.net/weixin_45855711/article/details/109477356 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
逛到本站,mark一下
[***.202.152.39]2024年03月31日 01时27分08秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
window10 caffe cpu-only安装
2019-04-26
YOLO-V3 Bbox预测解读
2019-04-26
论如何做到轻量级网络(Unet为例)
2019-04-26
Mask RCNN简图
2019-04-26
Cascade RCNN
2019-04-26
牛顿法
2019-04-26
对深度学习目前以及未来的看法 (AI时代可能延后,但总会到来)
2019-04-26
计算机网络应用层笔记
2019-04-26
地址栏输入网址enter查询后发生了什么
2019-04-26
计算机网络链路层知识点
2019-04-26
冲突域和广播域
2019-04-26
3NF分解(无损+4NF)
2019-04-26
计算机各层网络协议
2019-04-26
划分子网的意义
2019-04-26
AndroidQ 以上禁用 wifi 随机mac功能
2019-04-26
AngularJS学习之二:配置本地开发环境
2019-04-26
AngularJS学习之三:学习Angular
2019-04-26
AngularJS学习:Angular的模块
2019-04-26
Angular学习:控制器(未翻译完)
2019-04-26
Angular学习:$q
2019-04-26