二叉树的非递归遍历(统一的模板)
二叉树的非递归遍历
- 前言
- 树的存储结构
- 先序遍历
- 先序的递归遍历
- 先序的非递归遍历
- 中序遍历
- 中序的递归遍历
- 中序遍历的非递归算法
- 后序遍历
- 后序的递归遍历
- 后序的非递归遍历
- 层次遍历
- 层次遍历获得每一层的节点个数
前言
以下是本博主用c语言创建栈和队列的博文
栈
队列
二叉树的基本操作
在二叉树遍历的时候,默认是先左子树后右子树。先,中,后是针对什么时候读取根节点而言的。
先序,中序与后序都需要借助栈来实现。对于c没有栈,所以本博主在代码中的栈是自己用c语言写的栈(链式栈),你们也可以依照自己的来改。在c++中就可以直接用STL中的了。
先序与中序的非递归过程可以通过这个图片来理解。
后序的非递归过程可以通过这个图片来理解。
树的存储结构
//树的节点
typedef struct BiTNode {char data;struct BiTNode* left, * right;
}BiTNode,*BiTree;
先序遍历
先序的递归遍历
/* 先序遍历*/
//递归算法
void PreOrder(BiTree T) {if (T) {printf("%c ", T->data);PreOrder(T->left);PreOrder(T->right);}
}
先序的非递归遍历
算法思路
- 先将根节点压入栈中,用一个工作指针node(初始值为根节点)
- 步骤1 遍历当前节点node的左子树,直到左子树为空。(在这里输出)
- 步骤2 弹出栈顶的空指针
- 步骤3 如果栈没有空,将栈顶元素弹出赋值给node,将node->right压入栈
代码:
void PreOrder_S(BiTree T) {if (!T) return;LinkStack S = (SNode*)malloc(sizeof(SNode));init(S);//初始化链式栈,使其置为空Push_L(S, T); //将根节点压入BiTNode* node = Top_L(S); while (!empty(S)) {// 一直往左子树方向走,直到遇到空的节点while (node) {printf("%c ", node->data);node = node->left; //置当前节点为其左子树Push_L(S, node); //压入}//上面循环结束的时候,在最后压入了一个空节点Pop_L(S); //弹出空节点if (!empty(S)) {//从栈顶弹出元素赋值给nodenode = Top_L(S); Pop_L(S);node = node->right;//置为其右子树Push_L(S, node);//压入}}
}
中序遍历
中序的递归遍历
/* 中序遍历*/
//递归算法
void InOrder(BiTree T) {if (T) {InOrder(T->left);printf("%c ", T->data);InOrder(T->right);}
}
中序遍历的非递归算法
算法的基本思路:
- 先将根节点压入栈中,用一个工作指针node(初始值为根节点)
- 步骤1 遍历当前节点node的左子树,直到左子树为空。
- 步骤2 弹出栈顶的空指针
- 步骤3 如果栈没有空,将栈顶元素弹出赋值给node(在这里输出),将node->right压入栈
代码:
void InOrder_S(BiTree T) {if (!T) return;LinkStack S = (SNode*)malloc(sizeof(SNode));init(S);Push_L(S, T);BiTNode* node = Top_L(S);while (!empty(S)) {while (node) {node = node->left;Push_L(S, node);}Pop_L(S);//空指针退栈if (!empty(S)) {//从栈顶弹出元素赋值给nodenode = Top_L(S);Pop_L(S);printf("%c ", node->data);node = node->right;//置为其右子树Push_L(S, node);//压入}}}
后序遍历
后序的递归遍历
/* 后序遍历*/
//递归算法
void PostOrder(BiTree T) {if (T) {PostOrder(T->left);PostOrder(T->right);printf("%c ", T->data);}
}
后序的非递归遍历
算法的基本思路:
- 因为后序遍历的时候一个二叉树的根节点会访问两次
- 设置一个标记,在第一次访问的时候不用出栈,只用读取即可
- 在第二次访问时就出栈
- 步骤一 遍历当前节点node的左子树,直到左子树为空。
- 步骤二 弹出栈顶的空指针,设置flag = 1,T = NULL
- 步骤三 遍历该节点的右子树,如果右子树为空,或者已经访问两次了就出栈
- 否则 就node = node->right,然后将node压入栈中
代码:
void PostOrder_S(BiTree T) {if (!T) return;LinkStack S = (SNode*)malloc(sizeof(SNode));int flag;init(S);Push_L(S, T);BiTNode* node = Top_L(S);while (!empty(S)) {//向左移动到尽头while (node) {node = node->left;Push_L(S, node);}//空指针退栈Pop_L(S);//T指向 栈顶节点前一个已经访问过的节点//初始值为NULL,是栈顶节点右子树为空也可以直接输出了T = NULL;flag = 1;while (!empty(S) && flag) { //变循环了//取出当前栈顶元素node = Top_L(S);//右节点为空,或者右节点已经访问过了if (node->right == T) {printf("%c ", node->data);Pop_L(S);//T指向被访问的节点T = node;}else {//否则将右节点插入node = node->right;Push_L(S, node);//设置未被访问的标记flag = 0; }}}
}
层次遍历
/*层次遍历*/
void LevelOrder(BiTree T) {if (!T)return;LinkQueue Q;init(Q); //初始化队列push(Q, T);//将根节点压入队列while (!empty(Q)) {BiTNode* node = font(Q);pop(Q);printf("%c ", node->data);if (node->left)push(Q,node->left);if (node->right)push(Q, node->right);}}
层次遍历获得每一层的节点个数
思路:想比于普通的层次遍历只循环一次且只用到一个队列,这个算法需要用到两个队列,并且在一个循环中,还要嵌套一个循环。之前在每一次都将不为空的节点插入一个队列中,因此除非节点全部遍历在停止而不能得到具体的层的节点。因此我们将左右孩子的节点先放在一个辅助队列里边。直到将原队列的节点遍历完,那么该次遍历的就是该层节点,辅助队列里边的则是下一层的节点,在内层循环结束后,将辅助队列的元素赋值给原队列,同时层数+1。
void traverseByLevel(node* root) {if (root) {queue<node*>que;que.push(root);int level = 1; //记录当前层数while (que.size()) {queue<node*>assist;if (que.front() != root) { //第一行后都需要输出换行cout << endl;}bool flag = true;cout << "第" << level << "有" << que.size() << "个结点" << endl;while (que.size()) {node* p = que.front();que.pop();if (p->lchild) {assist.push(p->lchild);}if (p->rchild) {assist.push(p->rchild);}if (false == flag) { //每行第2个元素开始 输出元素时前面加空格cout << " ";}cout << p->data ;flag = false;}level++;que = assist;}}
}
二叉树的非递归遍历(统一的模板)相关推荐
- 刷题:二叉树的非递归遍历方式
二叉树的非递归的遍历方式 上篇博客记录了二叉树的递归遍历方式以及根据二叉树的遍历结果还原二叉树的内容. 本篇博客记录二叉树的非递归的遍历方式. 二叉树的非递归遍历需要借助栈来实现,而且三种遍历的方式的 ...
- 二叉树的非递归遍历(c/c++)
由于递归算法相对于非递归算法来说效率通常都会更低,递归算法会有更多的资源需要压栈和出栈操作(不仅仅是参数,还有函数地址等)由于编译器对附加的一些栈保护机制会导致递归执行的更加低效,使用循环代替递归算法 ...
- 数据结构-二叉树的非递归遍历
前面的章节我们实现了二叉树最基本的遍历方式:递归遍历,代码是如此的简洁:辣么我们为什么还要去学习二叉树的非递归遍历方式呢?众所周知,递归优点是将可以将复杂的问题简单化即大问题拆分成一个个小问题,那么它 ...
- c语言以顺序结构存储的二叉树的非递归遍历,C语言二叉树的非递归遍历实例分析...
本文以实例形式讲述了C语言实现二叉树的非递归遍历方法.是数据结构与算法设计中常用的技巧.分享给大家供大家参考.具体方法如下: 先序遍历: void preOrder(Node *p) //非递归 { ...
- 树:二叉树的非递归遍历算法
二叉树的递归遍历 二叉树的递归遍历算法,写法很简单,比如说前序遍历树,如下: //前序遍历 void PreOrderTraverse(BiTree tree) {if (NULL != tree){ ...
- 6-9 二叉树的非递归遍历 (20 分)
** 6-9 二叉树的非递归遍历 (20 分) ** 本题要求用非递归的方法实现对给定二叉树的 3 种遍历. 函数接口定义: void InorderTraversal( BinTree BT ); ...
- C/C++ 二叉树的非递归遍历(前序、中序、后序非递归遍历)
二叉树的非递归遍历C/C++实现: 非递归先序遍历代码: void PreOrderTraversal (struct tree* root) { //非递归先序遍历struct tree* t ...
- C语言实现二叉树的非递归遍历
C语言实现二叉树的非递归遍历: 代码解释: 非递归前序遍历:1> 首先建立一个二维指针,用来存储每个结点的地址,定义栈顶指针top,初始值为-1,并将根结点存入栈中,top++:2> 进入 ...
- 二叉树的非递归遍历(C语言实现)
上一篇讨论了二叉树的的递归遍历,这一次讨论二叉树的三种非递归遍历 二叉树的非递归遍历采用栈实现,首先给出二叉树和栈的定义 #define STACK_INIT_SIZE 100 #define STA ...
最新文章
- 在 Linux 上用 dust 代替 du更直观
- 10个解放双手实用在线工具,有些代码真的不用手写
- 锁优化:逃逸分析、自旋锁、锁消除、锁粗化、轻量级锁和偏向锁
- Dubbo注册中心宕机
- 浮层java_css保持浮层水平垂直居中的四种方法
- 【C#每日一贴】ArrayList 转换成byte数组
- 【NLP】选择目标序列:贪心搜索和Beam search
- 微信开发之 二维码生成类库
- 第六章 jQuery选择器
- 流水灯c语言代码switch,单片机C语言入门之六switch case语句流水灯
- 高颜值智能存储 华三魔术家M2无线云盘评测
- 如何快速调出软键盘_天生我材必有用 | 如何快速的计算和调用防火阀、调节阀、铝合金风口等材料价格...
- java万年历程序代码_JAVA万年历程序代码
- 【技术教程】如何调用宇视SDK实现摄像机的云台控制?
- MINIGUI3.2 设置按钮前景色
- 404 网站服务器错误怎么解决,网站404错误页面是什么意思,它有什么用?
- ICLR22 自监督graph learning------------AUTOMATED SELF-SUPERVISED LEARNING FORGRAPHS--- 密歇根州立
- 平面几何----用余弦定理证明海伦公式
- 计算机主机前后,电脑cpu后面的字母是什么意思
- 药品研发--工艺技术人员积分和职务考核评估管理办法
热门文章
- mysql model only_full_group_by_MySql版本问题sql_mode=only_full_group_by的完美解决方案
- 为什么要把进程/线程绑定到特定cpu核上运行?(cpu core id coreIdx)opdevsdk_sys_bindThreadCoreId()
- C语言函数 snprintf()(发送有限字符截断字符串输出到 str 所指向的字符串)(字符串拼接、截断拼接)
- word报错:题注或页码中不含章节编号。请使用“开始”选项卡上的“多级列表”按钮,然后选择链接到标题样式的编号方案(无法添加题注)
- NumPy复制数组之浅拷贝和深拷贝(注意,直接用等号不是复制,且切片会改变原数组!!!)ndarray.copy() ndarray.view()(view()只是改变shape形状,数据还是同一个)
- USB查看器 USB Device Tree Viewer(UsbTreeView.exe)的使用(重启Intel Realsense摄像头)
- python 如何将代码打包成exe可执行程序?(导出为exe可执行文件)pyinstaller
- python中常用的语句元素
- Java中sc在哪里关闭_node 中设置的session,在javasc 怎么获取
- 每天学一点儿shell:Linux三剑客——awk命令