树的遍历-深度优先遍历和广度优先遍历

2023-11-06

深度优先遍历类似于树的先序遍历。假设给定初态是图中所有顶点均未被访问过,从图中某一顶点vi出发遍历图中的定义如下:首先访问出发点vi,并将其访问标志置为1;然后,从vi出发点依次搜索vi的每个邻接点vj。如vj未被访问过,则以vj为新的出发点继续进行深度优先搜索。

广度优先遍历,类似于树的按层次遍历。设图G是连通的,且图G的初态是所有顶点均未被访问过。从图G的任一顶点vi出发按广度优先搜索遍历图的步骤是:访问vi后,依次访问与vi邻接的所有顶点w1,w2,w3......wn,再按w1,w2,w3......wn的顺序访问其中每个顶点的所有未被访问的邻接点,再按此顺序,依次访问它们所有未被访问的邻接点,以此类推,直到图中所有顶点均被访问过为止。

比如,以下面的图为例(包括不连通的顶点):


图中包括9个顶点,顶点序号为0~8,顶点信息为依次为字符 'a' ~ ' i',其中顶点8不与其他顶点相连通。

利用递归形式的深度优先遍历:

遍历结果:0->1->3->7->4->5->2->6 ->8         输出结果:a->b->d->h->e->f->c->g->i

利用非递归形式(栈)的深度优先遍历:

遍历结果:0->1->3->7->4->5->2->6 ->8         输出结果:a->b->d->h->e->f->c->g->i

利用广度优先遍历(队列):

遍历结果:0->1->2->3->4->5->6->7 ->8         输出结果:a->b->c->d->e->f->g->h->i


程序如下(有问题共同交流):

#include<iostream>
#include<assert.h>
#include<string>

#define NUM 9
#define MAXSIZE 15
using namespace std;

typedef struct graph
{
	char vertexs[NUM];
	int matrixs[NUM][NUM];
};

typedef struct stack
{
	int dataNum[MAXSIZE];
	int top;
	int stackSize;
};

typedef struct queue
{
	int dataArray[MAXSIZE];
	int front;
	int rear;
};

//直接创建图
void CreateGraph(graph * g);
//深度优先遍历(递归形式)图中所有连通顶点,打印顶点信息
void DFS(graph* g, int i, int visit[NUM]);
//深度优先遍历(递归形式)图中剩余其他顶点,打印顶点信息
void FinalDFS(graph* g, int visit[NUM]);

//创建栈
void CreateStack(stack *s);
//判断栈是否为空
int EmptyStack(stack *s);
//将顶点序号入栈
void PushStack(stack *s, int k);
//出栈,取栈顶元素
int PopStack(stack *s);
//利用栈,深度优先遍历(非递归形式)图中每个顶点
void DFS_Stack(graph *g, int i, stack* s, int visit[NUM]);
//利用栈,深度优先遍历(非递归形式)图中所有顶点
void FinalDFS_Stack(graph *g, stack* s, int visit[NUM]);

//创建队列
void CreateQueue(queue *q);
//判断队列是否为空
int EmptyQueue(queue *q);
//入队,将顶点序号入队
void ENQUEUE(queue *q, int e);
//出队,将队头元素出队
int DEQUEUE(queue *q);
//利用队列,广度优先遍历图中和源点i相连通的所有顶点
void BFS_Queue(graph *g, int i, queue* q, int visit[NUM]);
//利用队列,广度优先遍历图中所有顶点(包括不连通顶点)
void FinalBFS_Queue(graph *g, queue* q, int visit[NUM]);


int main()
{
	graph g;
	CreateGraph(&g);
	int visit[NUM] = {0};

	//利用深度优先搜索遍历(递归形式)
	printf("深度优先遍历(递归形式): ");
	FinalDFS(&g,visit);
	printf("\n");

	//利用深度优先遍历(非递归形式:栈)
	printf("深度优先遍历(非递归形式 栈): ");
	int visit1[NUM] = { 0 };
	stack s;
	CreateStack(&s);
	FinalDFS_Stack(&g, &s, visit1);
	printf("\n");

	//利用广度优先遍历(队列)
	printf("广度优先遍历(队列): ");
	int visit2[NUM] = { 0 };
	queue q;
	CreateQueue(&q);
	FinalBFS_Queue(&g, &q, visit2);
	printf("\n");

	return 0;
}

//创建图
void CreateGraph(struct graph * g)
{
	//默认9个顶点信息依次为字符"a b c d e f g h i"
	for (int i = 0; i < NUM; i++)
	{
		g->vertexs[i] = 'a'+i;
	}

	//直接创建图的邻接矩阵
	g->matrixs[0][1] = 1;
	g->matrixs[0][2] = 1;

	g->matrixs[1][0] = 1;
	g->matrixs[1][3] = 1;
	g->matrixs[1][4] = 1;

	g->matrixs[2][0] = 1;
	g->matrixs[2][5] = 1;
	g->matrixs[2][6] = 1;

	g->matrixs[3][1] = 1;
	g->matrixs[3][7] = 1;

	g->matrixs[4][1] = 1;
	g->matrixs[4][7] = 1;

	g->matrixs[5][2] = 1;
	g->matrixs[5][7] = 1;

	g->matrixs[6][2] = 1;
	g->matrixs[6][7] = 1;

	g->matrixs[7][3] = 1;
	g->matrixs[7][4] = 1;
	g->matrixs[7][5] = 1;
	g->matrixs[7][6] = 1;
}


//深度优先遍历(递归形式)图中所有联通顶点,打印顶点信息
void DFS(graph* g, int i, int visit[NUM])
{
	//将访问到的顶点的标志位赋1
	visit[i] = 1;
	//打印访问到的顶点信息
	printf("%c ", g->vertexs[i]);
	for (int j = 0; j < NUM; j++)
	{
		if (g->matrixs[i][j]==1 && visit[j]==0)
		{
			DFS(g,j,visit);
		}
	}
}

//深度优先遍历(递归形式)图中所有顶点,打印顶点信息
void FinalDFS(graph* g, int visit[NUM])
{

	//遍历所有顶点
	for (int m = 0; m < NUM; m++)
	{
		if (visit[m] == 0)
		{
			DFS(g, m, visit);
		}
	}
}

//创建栈
void CreateStack(stack *s)
{
	//将栈置空
	s->top = -1;
	s->stackSize = MAXSIZE;
}

//判断栈是否为空
int EmptyStack(stack *s)
{
	if (s->top==-1)  return 1;
    else return 0;
}

//将顶点序号入栈
void PushStack(stack *s, int k)
{
	if (s->top == (s->stackSize-1))
	{
		printf("overflow");
		return;
	}
	else
	{
		s->top++;
		s->dataNum[s->top] = k;
	}
}

//出栈,取栈顶元素
int PopStack(stack *s)
{
	if (EmptyStack(s)==1)
	{
		return -1;
	}
	else
	{
		int vexNum=s->dataNum[s->top];
		s->top--;
		return vexNum;
	}
}

//利用栈,深度优先遍历(非递归形式)图中每个顶点
void DFS_Stack(graph *g, int i, stack* s, int visit[NUM])
{
	visit[i] = 1;
	//将第一个顶点入栈
	PushStack(s,i);
	//打印第一个顶点信息
	printf("%c ",g->vertexs[s->dataNum[s->top]]);
	while (s->top!=-1)
	{
		int x = s->dataNum[s->top];
		int flag = 0;
		for (int j = 0; j < NUM;j++)
		{
			if (g->matrixs[x][j] == 1 && visit[j] == 0)
			{
				visit[j] = 1;
				PushStack(s,j);
				flag = 1;
				printf("%c ", g->vertexs[s->dataNum[s->top]]);
				break;
			}
		}	
		if (flag==0)
		{		
			PopStack(s);
		}  
	}
}

//利用栈,深度优先遍历(非递归形式)图中所有顶点
void FinalDFS_Stack(graph *g, stack* s, int visit[NUM])
{

	//遍历所有顶点
	for (int m = 0; m < NUM; m++)
	{
		if (visit[m] == 0)
		{
			DFS_Stack(g, m, s, visit);
		}
	}
}

//创建队列
void CreateQueue(queue *q)
{
	q->front = q->rear = 0;
}

//判断队列是否为空
int EmptyQueue(queue *q)
{
	if (q->front == q->rear) return 1;
	else return 0;
}

//入队,将顶点序号入队
void ENQUEUE(queue *q, int e)
{
	if (q->rear-q->front==(MAXSIZE-1))
	{
		printf("队满上溢");
		return;
	}
	else
	{
		q->dataArray[q->rear] = e;
		q->rear++;
	}
}

//出队,将队头元素出队
int DEQUEUE(queue *q)
{
	if (EmptyQueue(q)==1)
	{
		return -1;
	}
	else
	{
		int frontNum =q->dataArray[q->front];
		q->front++;
		return frontNum;
	}
}

//利用队列,广度优先遍历图中和源点i相连通的所有顶点
void BFS_Queue(graph *g, int i, queue* q, int visit[NUM])
{
	visit[i] = 1;
	//将第一个顶点入队
	ENQUEUE(q,i);
	//打印第一个顶点信息
	//printf("%c ", q->dataArray[q->front]);

	while (EmptyQueue(q)!=1)
	{
		int k = DEQUEUE(q);
		printf("%c ", g->vertexs[k]);
		for (int j = 0; j < NUM;j++)
		{
			if (g->matrixs[k][j] == 1 && visit[j] == 0)
			{
				visit[j] = 1;
				ENQUEUE(q, j);
			}
		}
	}
}

//利用队列,广度优先遍历图中所有顶点(包括不连通顶点)
void FinalBFS_Queue(graph *g, queue* q, int visit[NUM])
{
	//遍历所有顶点
	for (int m = 0; m < NUM; m++)
	{
		if (visit[m] == 0)
		{
			BFS_Queue(g, m, q, visit);
		}
	}
}

输出结果如下:


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

树的遍历-深度优先遍历和广度优先遍历 的相关文章

  • C语言/C++实现栈操作

    一 栈的概念 栈是一种常用的数据结构 它遵循先入后出 Last In First Out LIFO 的原则 栈的操作只在栈的一端进行 该端被称为栈顶 而另一端称为栈底 栈的基本操作包括压栈 入栈 push 和弹栈 出栈 pop 分别用于将元
  • 数据结构中常见的树(BST二叉搜索树、AVL平衡二叉树、RBT红黑树、B-树、B+树、B*树)

    原文 http blog csdn net sup heaven article details 39313731 数据结构中常见的树 BST二叉搜索树 AVL平衡二叉树 RBT红黑树 B 树 B 树 B 树 转载 2014年09月16日
  • 《Linux From Scratch》第三部分:构建LFS系统 第六章:安装基本的系统软件- 6.29. Coreutils-8.23...

    Coreutils 软件包包含用于显示和设置基本系统特性的工具 大概编译时间 2 5 SBU 需要磁盘空间 193 MB 6 29 1 安装 Coreutils POSIX 要求 Coreutils 中的程序即使在多字节语言环境也能正确识别
  • 直线检测方法—LSD论文翻译

    附原文链接 LSD a Line Segment Detector 摘 要 LSD是一个线段检测器 能够在线性时间内得到亚像素级精度的检测结果 它无需调试参数就可以适用于任何数字图像上 并且能够自我控制错误数量的检测 平均来说 一个图像中允
  • 数据结构之链表与线性表

    数据结构之链表与线性表 线性表 顺序线性表 顺序表 顺序线性表 使用数组实现 一组地址连续的存储单元 数组大小有两种方式指定 一是静态分配 二是动态扩展 优点 随机访问特性 查找O 1 时间 存储密度高 逻辑上相邻的元素 物理上也相邻 缺点
  • 一文弄懂循环链表、双向链表、静态链表

    循环链表 双向链表 静态链表 三遍定律 理解了单链表本文的理解易如反掌 单链表请点击这里 理解了单链表本文的理解易如反掌 单链表请点击这里 理解了单链表本文的理解易如反掌 单链表请点击这里 1 循环链表 将单链表中终端结点的指针端由空指针改
  • 4399 C++笔试题

    1 写出一个函数 取到链表中倒数第二个节点 双链表 node getSec List mylist return mylist m tail gt m prev m prev为链表前指针 单链表 node getSec List mylis
  • findBug 错误修改指南

    FindBugs错误修改指南 1 EC UNRELATED TYPES Bug Call to equals comparing different types Pattern id EC UNRELATED TYPES type EC c
  • 以太坊系列之十五: 以太坊数据库

    以太坊数据库中都存了什么 以太坊使用的数据库是一个NOSQL数据库 是谷歌提供的开源数据leveldb 这里尝试通过分析以太坊数据库存储了什么来分析以太坊可能为我们提供哪些关于区块链的API 存储内容 NOSQL是一个key value数据
  • 链表面试题(一):反转链表的算法实现

    关于链表的考察 链表是面试里面经常涉及到的考点 因为链表的结构相比于Hashmap Hashtable Concurrenthashmap或者图等数据结构简单许多 对于后者更多面试的侧重点在于其底层实现 比如Hashmap中Entry
  • 图 - Java实现无向带权图的邻接矩阵表示法

    图 Java实现无向带权图的邻接矩阵表示法 1 图 1 1 图的介绍 图 Graph 是一种复杂的非线性表结构 图中的元素我们就叫做顶点 vertex 图中的一个顶点可以与任意其他顶点建立连接关系 我们把这种建立的关系叫做边 edge 跟顶
  • 数据结构——计算节点个数和二叉树高度(C语言版)

    摘自 数据结构 计算节点个数和二叉树高度 C语言版 作者 正弦定理 发布时间 2020 12 12 23 27 09 网址 https blog csdn net chinesekobe article details 111086664
  • 如何防止过拟合和欠拟合

    过拟合和欠拟合是模型训练过程中经常出现的问题 两种情况正好相反 现将两者的定义及如何防止进行简要总结 1 过拟合 1 1 定义 是指模型对于训练数据拟合呈现过当的情况 反映到评估指标上就是模型在训练集上的表现很好 但是在测试集上的表现较差
  • 时间复杂度+常见复杂度解释

    前言 算法的效率 虽然计算机能快速的完成运算处理 但实际上 它也需要根据输入数据的大小和算法效率来消耗一定的处理器资源 要想编写出能高效运行的程序 我们就需要考虑到算法的效率 算法的效率主要由以下两个复杂度来评估 时间复杂度 评估执行程序所
  • LeetCode 98. 验证二叉搜索树(C++)

    1 题目如下 给你一个二叉树的根节点 root 判断其是否是一个有效的二叉搜索树 有效 二叉搜索树定义如下 节点的左子树只包含 小于 当前节点的数 节点的右子树只包含 大于 当前节点的数 所有左子树和右子树自身必须也是二叉搜索树 示例 1
  • Leetcode1094. 拼车

    Every day a Leetcode 题目来源 1094 拼车 解法1 差分数组 对于本题 设 a i 表示车行驶到位置 i 时车上的人数 我们需要判断是否所有 a i 都不超过 capacity trips i 相当于把 a 中下标从
  • 数组实现循环队列(增设队列大小size)

    目录 一 前言 1 如何实现循环 2 如何判断队列为空 3 如何判断队列为满 二 循环队列的结构定义 三 循环队列的创建及其初始化 四 入队 五 出队 六 取队头元素 七 取队尾元素 八 循环队列判空 九 循环队列判满 十 循环队列销毁 一
  • 【数据结构入门精讲 | 第二篇】一文讲清算法复杂度

    上篇文章中我们引入了算法 数据结构 数据类型等概念 而要想衡量一个算法与数据结构是否为优质的 就需要一个衡量标准 这个衡量标准也是在我们实现一个好的算法时要遵循的原则 目录 基本概念 渐进性态 渐进性态数学表征 算法复杂度的运算 顺序搜索算
  • 浅谈归并排序:合并 K 个升序链表的归并解法

    在面试中遇到了这道题 如何实现多个升序链表的合并 这是 LeetCode 上的一道原题 题目具体如下 用归并实现合并 K 个升序链表 LeetCode 23 合并K个升序链表 给你一个链表数组 每个链表都已经按升序排列 请你将所有链表合并到
  • 高精度运算合集,加减乘除,快速幂,详细代码,OJ链接

    文章目录 零 前言 一 加法 高精度加法步骤 P1601 A B 二 减法 高精度减法步骤

随机推荐

  • Android平台安全(一)

    刚好五一了 已经过去两三天了 今天接触到了关于Android安全的一些东西 记录下来 Android安全我大致分三个部分来说明 今天我就先说第一个部分 在典型的场景中 安全主要用于解决一下4类需求 保密 鉴别 认证 完整性 不可以否认性 安
  • IncrediBuild 联合编译

    01 基本信息 官网 https www incredibuild com Make 和其他构建工具示例 要使用IncrediBuild 必须有License 可以免费申请试用版本的license 可以到 https www incredi
  • 【H5】两种加密解密方法:

    H5 两种加密解码方法 encodeURI 加密 decodeURI 解密 加密成base64编码格式 btoa 加密 atob 解密 实现代码如下
  • 【C语言】计数排序

    一 算法描述 得到最小值和最大值 即得到临时数组的长度 数等于临时数组的下标 下标对应的值就加一 把临时数组的信息对应到原数组中 计数排序有很大的约束 最小值和最大值不能相差很大 排序的数适用于非负数 否则得另加代码将负数偏移为正数 最后还
  • MySQL——存储过程详解及实例分析

    目录 一 储存过程简介 1 什么是存储过程 2 存储过程优缺点 3 存储过程入门程序 4 在idea中如何调用储存过程 二 存储过程编程 1 存储过程的变量 2 存储过程中的参数 3 选择结构if 4 分支结构case 5 3个循环结构 6
  • 中文分词jieba学习笔记

    中文分词jieba学习笔记 一 分词模式 二 自定义词典 2 1 命令 2 2 使用方式 三 关键词抽取 基于TF IDF算法 3 1 用jieba analyse extract tags 3 2 用jieba analyse textr
  • idea配置tomcat启动服务器时控制台乱码

    项目场景 在idea中配置tomcat启动时候控制台乱码问题 问题描述 idea中以tomcat启动控制台出现乱码问题 原因分析 由于tomcat8以后默认编码格式是utf 8 tomcat7之前的都是iso8859 1 与idea中的编码
  • 反激式开关电源双环PID(电压环+电流环)控制之MATLAB仿真

    前面一篇文章我讲解了反激式开关电源输出电压的pid控制的matlab仿真 反激式开关电源输出电压PID控制的MATLAB仿真 我只对输出电压做了控制 不管负载多大 只要在设计功率之内 都能把电压维持在12V 但在实际电路设计中 我们还需要考
  • Box2D C++ 教程 第五节:物体(Bodies)

    Box2D C 教程 第五节 物体 Bodies 作者 firedragonpzy 14 十一月 2012 暂无评论 声明 本教程翻译自 Box2D C tutorials Bodies 仅供学习参考 物体 Bodies 物体是物理场景中的
  • 【踩坑】jmeter提取token,响应body中全部是token无法用正则提取

    情况是这样的 这是jmeter的响应结果 响应所有文本都是token 尝试了多次用正则提取 均无法提取全部body 经过查询资料 使用BeanShell 后置处理程序 import org json JSONObject import or
  • 【数据分析】【Pandas】(一)如何制作频率分布直方图

    文章目录 概述 1 直方图 2 密度图 概述 计算一组数据的分布有助于我们更好的了解数据构成 我们可以通过直方图或密度图 将离散的数据通过连续的方式展现出来 数据分布 频数分布 在各组按顺序排列的基础上 列出每个组的总体单位数 形成一个数列
  • nuxtjs 国际化i18n

    1 设置国际化匹配文字 locales zh json locales en json 英文同理 topbar home 首页 pin 沸点 topic 话题 book 小册 search 搜索 menu home 我的主页 label 标
  • 【计算机毕业设计】高校信息资源共享平台

    高校信息资源共享平台 21世纪的今天 随着社会的不断发展与进步 人们对于信息科学化的认识 已由低层次向高层次发展 由原来的感性认识向理性认识提高 管理工作的重要性已逐渐被人们所认识 科学化的管理 使信息存储达到准确 快速 完善 并能提高工作
  • 什么是企业用户画像,怎么构建企业用户画像

    企业画像 简单说 企业给人的印象 可以跟自然人的用户画像相类比 这其实是IT行业的一种叫法 在金融行业 一般叫做 尽职调查报告 当然 尽职调查报告只需要尽职 不需要说的太具体或者太难看 什么是企业用户画像 企业用户画像与个人用户画像有很大区
  • 反射/存储/DOM型XSS攻击原理及攻击流程详解

    文章目录 XSS漏洞原理 1 XSS分类 1 1 攻击流程 2 存储型XSS 2 1 攻击流程 3 DOM型XSS 3 1 攻击流程 XSS修复 XSS漏洞原理 XSS 跨站脚本攻击 是一种常见的 Web 安全漏洞 其允许攻击者在恶意用户的
  • 新版caffe添加自己的层(目前只学会添加,我想要添加的loss还没能实现)

    今天实现了在caffe框架中加入一个层 完成欧式距离的任务 之所以这样 是因为还没有实现自己想要的loss 只是试着学者 看能不能把添加层的流程顺下来 最后实现了 一 总体框架 1 在 src caffe proto caffe proto
  • SpringCache的介绍和使用

    1 简介 1 Spring 从 3 1 开始定义了 org springframework cache Cache和 org springframework cache CacheManager 接口来统一不同的缓存技术 并支持使用 JCa
  • 六、IP地址子网划分与VLAN

    一 IP地址的五大分类 概念 IP地址相当于人的身份证 用于在TCP IP通信协议中标记每台计算机的地址 通常用于十进制来表示 如192 168 1 100 但是在计算机内部 IP地址是一个32位的二进制数值 如11000000 10101
  • [转载]Chrome 与 Chrome OS 各版本下载集合

    Chrome OS 下载 由 Hexxeh提供的第三方编译版本 Chrome OS USB 镜像 点击这里 Chrome OS WMware 镜像 点击这里 Chrome OS Vanilla USB VMWare VirtualBox 点
  • 树的遍历-深度优先遍历和广度优先遍历

    深度优先遍历类似于树的先序遍历 假设给定初态是图中所有顶点均未被访问过 从图中某一顶点vi出发遍历图中的定义如下 首先访问出发点vi 并将其访问标志置为1 然后 从vi出发点依次搜索vi的每个邻接点vj 如vj未被访问过 则以vj为新的出发