遍历二叉树 - 基于队列的BFS
之前学过利用递归实现BFS二叉树搜索(http://www.cnblogs.com/webor2006/p/7262773.html),这次学习利用队列(Queue)来实现,关于什么时BFS这里不多说了,先贴张图来直观回忆下:

实现一个队列【采用数组实现】:
这时同样采用模版技术可以往队列中去放任何类型的数据,而这个队列同样是声明在头文件中,以便在需要用到队列的地方去随时包含它,下面先来定个初步框架:
/**
* 利用数组来实现队列
*/ template <typename T> class queue
{
T* data;//用数组来实现队列
int head/* 头指向的位置 */, tail/* 尾指向的位置 */, size/* 当前队列存放的元素个数 */, data_length/* 总队列的大小 */;
public:
queue(int length):head(), tail(), size(), data_length(length) {
data = new T[length];
} //入队列
void push(T value) { } //出队列
void pop() { } //取出队列最早的元素
T top() { } //判断队列是否为空
bool isEmpty() { }
};
具体实现如下:
/**
* 利用数组来实现队列
*/ template <typename T> class queue
{
T* data;//用数组来实现队列
int head/* 头指向的位置 */, tail/* 尾指向的位置 */, size/* 当前队列存放的元素个数 */, data_length/* 总队列的大小 */;
public:
queue(int length):head(), tail(), size(), data_length(length) {
data = new T[length];
} //入队列
void push(T value) {
if(size == data_length) {
throw "queue is full";//如果队列已经满了则直接抛异常,实际可以去将数组扩容,这里简单处理,重在学习数据结构
}
data[head] = value;
head = (head + ) % data_length;//这是为了循环利用,如果队列还有空间的话
size++;
} //出队列
void pop() {
if(isEmpty()) {
throw "queue is empty";
}
tail = (tail + ) % data_length;//这是为了循环利用
size--;
} //取出队列最早的元素
T top() {
if(isEmpty())
throw "You cannot get the top element from an empty queue";
return data[tail];
} //判断队列是否为空
bool isEmpty() {
return size == ;
}
};
这里先来使用一下它,看入队跟出队的结果是否如预期:

编译运行:

对于上面的写法下面用图来将其整个过程画出来:
①、
创建一个大小为3的队列,其中head、tail指向数组0的位置,其中目前是一个size=0空数组

②、
往队列中插入元素1:

③、
往队列中插入元素2:
④、
往队列中插入元素3,这里需要注意啦!!!head会循环利用,指向数组0的位置:

⑤、
根据队列先进先出的原则拿最早放入的元素也就是tail所指向的元素:

⑥、
根据队列先进先出的原则拿最早放入的元素也就是tail所指向的元素:
⑦、
根据队列先进先出的原则拿最早放入的元素也就是tail所指向的元素:
这时注意啦!!!tail跟head一样也会循环利用,又回到index=0的位置了:

⑧、
由于此时size=0了,所以会打印出"queue is empty"。
⑨、

⑩、

⑪、
由于此时size=0了,所以会打印出"queue is empty"。
总结:
1、添加元素放到head处,添加完成之后将head+1以便下次进行存放。
2、拿元素时是从tail处拿,拿完之后也是将tail+1以便拿下一个元素,因为是先进先出原则。
基于上节的实现来利用队列实现二叉树的BFS遍历:
先贴一下上节的代码,基于这个二叉树利用队列去实现:
#include <iostream>
#include "stack.h"
#include "queue.h" //用来表示二叉树
struct treenode{
int data;
treenode* left;//左结点
treenode* right;//右结点
treenode(int value):data(value), left(nullptr), right(nullptr){}
}; //前序遍历
void pre_order(treenode* root){
Stack<treenode*> stack;//声明一个栈
treenode* current_node = root;
while(current_node) {
//1、首先打印当前结点,因为是前序遍历
std::cout << current_node->data << std::endl;
//2、如果存在右结点则将其入栈暂存,待左结点输出完之后再去处理这些右结点
if(current_node->right) stack.push(current_node->right);
//3、不断去处理左结点,直到左结点处理完了,则从栈中拿右点进行处理
if(current_node->left)//如果有左结点,则将它做为当前处理的结点不断输出
current_node = current_node->left;
else {
//这时左结点已经处理完了
if(stack.isEmpty())//如果缓存栈已经为空了则说明整个二叉树的遍历结束了
current_node = nullptr;
else {
//则取出栈顶的右结点进行处理,由于是后进先出,所以拿出来的永远是最新插入的右结点
current_node = stack.top();
stack.pop();//将其元素从栈顶弹出
} }
}
} //利用队列实现BFS
void level_order(treenode* root){
//TODO
} int main(void) { //构建二叉树:
//1、第一层根结点
treenode* root = new treenode();
//2、第二层结点
root->left = new treenode();
root->right = new treenode();
//3、第三层结点
root->left->left = new treenode();
root->left->right = new treenode();
root->right->left = new treenode();
//4、第四层结点
root->right->left->left = new treenode(); pre_order(root); std::cout << "##################" << std::endl; level_order(root); return ;
}
其二叉树为:
下面具体来实现level_order:

只要理解的队列的先进先出的特点上面的实现比较容易理解,不多解释,编译运行:

下面看一下它的时间复杂度:由于队列中有多少元素就会遍历多次次,所以很明显是O(n)。
遍历二叉树 - 基于队列的BFS的更多相关文章
- 遍历二叉树 - 基于栈的DFS
之前已经学过二叉树的DFS的遍历算法[http://www.cnblogs.com/webor2006/p/7244499.html],当时是基于递归来实现的,这次利用栈不用递归也来实现DFS的遍历, ...
- 遍历二叉树 - 基于递归的DFS(前序,中序,后序)
上节中已经学会了如何构建一个二叉搜索数,这次来学习下树的打印-基于递归的DFS,那什么是DFS呢? 有个概念就行,而它又分为前序.中序.后序三种遍历方式,这个也是在面试中经常会被问到的,下面来具体学习 ...
- java二叉树遍历——深度优先(DFS)与广度优先(BFS) 递归版与非递归版
介绍 深度优先遍历:从根节点出发,沿着左子树方向进行纵向遍历,直到找到叶子节点为止.然后回溯到前一个节点,进行右子树节点的遍历,直到遍历完所有可达节点为止. 广度优先遍历:从根节点出发,在横向遍历二叉 ...
- 基于循环队列的BFS的原理及实现
文章首发于微信公众号:几何思维 1.故事起源 有一只蚂蚁出去寻找食物,无意中进入了一个迷宫.蚂蚁只能向上.下.左.右4个方向走,迷宫中有墙和水的地方都无法通行.这时蚂蚁犯难了,怎样才能找出到食物的最短 ...
- 基于visual Studio2013解决面试题之0401非递归遍历二叉树
题目
- 基于递归的BFS(Level-order)
上篇中学习了二叉树的DFS深度优先搜索算法,这次学习另外一种二叉树的搜索算法:BFS,下面看一下它的概念: 有些抽象是不?下面看下整个的遍历过程的动画演示就晓得是咋回事啦: 了解其概念之后,下面看下如 ...
- UVa 122 Trees on the level (动态建树 && 层序遍历二叉树)
题意 :输入一棵二叉树,你的任务是按从上到下.从左到右的顺序输出各个结点的值.每个结 点都按照从根结点到它的移动序列给出(L表示左,R表示右).在输入中,每个结点的左 括号和右括号之间没有空格,相邻 ...
- Java遍历二叉树深度宽度
节点数据结构 class TreeNode { TreeNode left = null; TreeNode right = null; } 最大深度,基本思路是:使用递归,分别求出左子树的深度.右子 ...
- PHP遍历二叉树
遍历二叉树,这个相对比较复杂. 二叉树的便利,主要有两种,一种是广度优先遍历,一种是深度优先遍历. 什么是广度优先遍历?就是根节点进入,水平一行一行的便利. 什么是深度优先遍历呢?就是根节点进入,然后 ...
随机推荐
- sed工具的基本用法
sed文本处理工具的用法: 用法1:前置命令 | sed [选项] '条件指令' 用法2:sed [选项] '条件指令' 文件.. .. 认识sed工具的基本选项 sed命令的常用选项如下: -n(屏 ...
- python 智能玩别踩白块
# encoding :utf-8import pyautoguifrom PIL import Imageimport time pyautogui.FAILSAFE = True time.sle ...
- 日常工作问题解决:centos/linux系统如何检测端口是否打开
1.telnet命令 格式: telnet ip 端口号 [root@centos7-127 ~]# telnet 192.168.87.128 22 Trying 192.168.87.128... ...
- 学习笔记:CentOS7学习之十八:Linux系统启动原理及故障排除
目录 学习笔记:CentOS7学习之十八:Linux系统启动原理及故障排除 18.1 centos6系统启动过程及相关配置文件 18.1.1 centos6系统启动过程 18.1.2 centos6启 ...
- 小程序部分机型上一个诡异的偶现bug
如上图所示:开始的时候进到下单页面,价格是0,当选中了商品产生价格的时候,生成的价格如 ¥150,这个时候会只露出¥1以及一小半的5,后面的都被遮挡住了. wxml里是这样的写的 <view w ...
- hdoj3586 (树形dp)
题目链接:https://vjudge.net/problem/HDU-3586 题意:一棵边权树,要删掉一些边使得每个叶子结点不能到达树根,且这些边的权值<=上限Max,且边权和小于m,求最小 ...
- [Cometoj#4 B]奇偶性_打表
奇偶性 题目链接:https://cometoj.com/contest/39/problem/B?problem_id=1577 数据范围:略. 题解: 因为$f$的构造原因,很容易找到规律. 进而 ...
- 【3.4】innodb存储引擎
[1]Innodb 与 Myisam 的区别 1.InnoDB支持事物,而MyISAM不支持事物 2.InnoDB支持行级锁,而MyISAM支持表级锁 3.InnoDB支持MVCC, 而MyISAM不 ...
- [转] zookeeper 本地启动多节点
1. zoo.cfg配置文件如下: # The number of milliseconds of each tick tickTime=2000 # The number of ticks that ...
- ubuntu下java的安装与执行
一.安装java sudo add-apt-repository ppa:linuxuprising/java sudo apt-get update sudo apt-get install ora ...