二叉树的非递归的遍历方式

上篇博客记录了二叉树的递归遍历方式以及根据二叉树的遍历结果还原二叉树的内容。

本篇博客记录二叉树的非递归的遍历方式。

二叉树的非递归遍历需要借助栈来实现,而且三种遍历的方式的算法难易程度并不相同。其中,先序遍历较为简单,中序遍历稍难,后序遍历最伤脑筋。下面分别说一说三种非递归遍历算法的实现方式。

1. 非递归先序遍历

如上所述,非递归先序遍历方式较为简单。其主要思想是:

  1. 将二叉树的根节点压入栈中。
  2. 获取栈顶元素P并打印其值,做出栈操作。
  3. p的右节点存在,将其压入栈中。
  4. p的左节点存在,将其压入栈中。
  5. 如果栈不为空的话,重复2-4操作。

这种方法说的直白一点就是先读取栈顶节点,然后在将该节点的子节点按照先右后左的方式入栈。这样就保证了在每次循环过程中都能先访问根节点,再以先序的方式遍历左子树和右子树。

void PreTraverseNoRecursion(BiTree T)
{    //BiTree  与TreeNode* 是相同类型stack<TreeNode*> temp_stack;TreeNode* temp_node;temp_stack.push(T);do {temp_node = temp_stack.top();cout << temp_node->data << " ";temp_stack.pop();if (temp_node->Rchild)temp_stack.push(temp_node->Rchild);if (temp_node->Lchild)temp_stack.push(temp_node->Lchild);} while (!temp_stack.empty());}

2.非递归中序遍历

非递归的中序遍历要比先序遍历难一些,主要是不容易思考全面。
非递归中序遍历的主要思想是:

  1. 定义一个结点指针p,使其指向根节点。
  2. p不为空或栈不为空,将根节点和二叉树最左边的各个节点逐个压入栈中。中序遍历必须先访问左子树,因此要把根节点和二叉树最左边的各个节点逐个压入栈中。这个过程能够保证栈顶的节点是整个二叉树最左边最底层的节点,该节点不存在左子树。
  3. 访问栈顶节点q并出栈。
  4. p等于q的右节点。节点q不存在左子树,但不一定不存在右子树。若其存在右子树,令p等于q的右节点,相当于让p作为一颗新二叉树的根节点,重复2-3操作。若q没有右子树,p将访问栈中新的顶节点。
  5. 重复2-4操作。
void MidTraverseNoRecursion(BiTree T)
{stack<TreeNode*> temp_stack;TreeNode* temp_node = T;while (temp_node || !temp_stack.empty()){while (temp_node){temp_stack.push(temp_node);temp_node = temp_node->Lchild;}temp_node = temp_stack.top();cout << temp_node->data << " ";temp_stack.pop();temp_node = temp_node->Rchild;}
}

3.非递归后序遍历

非递归后序遍历是三种非递归遍历算法中最难的一种,而它难就难在需要另外一个指针来记录上一次访问的节点。
其主要思想是:

  1. 定义两个节点指针cur_node 和last_node,并使他们指向根节点。
  2. 将根节点压入栈中。
  3. 若栈不为空,则令cur_node指向栈顶节点。
  4. 若 (cur_node指向节点没有子节点) 或 (cur_node指向节点的右节点为空 且last_node指向的节点为当前节点的左节点) 或 (last_node指向的节点为当前节点的右节点),则访问该节点并出栈。否则将该节点的子节点按照先右后左的方式入栈。
  5. 重复3-4操作。

该方法不易想到,但是想到后理解起来也很容易。其实它要做的就是先将节点从根节点开始按照先右后左的顺序存入栈中,直到找到最左边最底层的叶节点L。找到该叶节点后对其进行访问,然后令last_node指向它,用已标记,并进行出栈操作,表示完成该节点的访问。若L的父节点存在右节点(即L存在兄弟节点),则此时栈顶元素应该是这个L的兄弟节点(称其为b)。若b无子节点,则对其访问,并用last_node进行标记,然后出栈。否则将其子节点入栈。如果完成了对L 的访问,且b不存在,则访问其父节点,然后出栈。该过程由cur_node ->Rchild == NULL && last_node == cur_node ->Lchild 条件控制。如果完成了对Lb的访问,则访问其父节点,然后出栈。该过程由last_node == cur_node ->Rchild条件控制。

理解清楚之后也不是很难。

void PostTTraverseNoRecursion(BiTree T)
{stack<TreeNode*> temp_stack;TreeNode* cur_node = T;TreeNode* last_node = T;temp_stack.push(T);while (!temp_stack.empty()){cur_node = temp_stack.top();if ((cur_node ->Lchild == NULL && cur_node ->Rchild == NULL) || (cur_node ->Rchild == NULL && last_node == cur_node ->Lchild) || (last_node == cur_node ->Rchild)){cout << cur_node ->data << " ";last_node = cur_node ;temp_stack.pop();}else{if (cur_node ->Rchild)temp_stack.push(cur_node ->Rchild);if (temp_node->Lchild)temp_stack.push(cur_node ->Lchild);}}
}

若有人看到本篇博客,那我就送他一句话:世界上就怕认真二字,格物致知方能有所收获。

刷题:二叉树的非递归遍历方式相关推荐

  1. 数据结构-二叉树的非递归遍历

    前面的章节我们实现了二叉树最基本的遍历方式:递归遍历,代码是如此的简洁:辣么我们为什么还要去学习二叉树的非递归遍历方式呢?众所周知,递归优点是将可以将复杂的问题简单化即大问题拆分成一个个小问题,那么它 ...

  2. 二叉树的非递归遍历(c/c++)

    由于递归算法相对于非递归算法来说效率通常都会更低,递归算法会有更多的资源需要压栈和出栈操作(不仅仅是参数,还有函数地址等)由于编译器对附加的一些栈保护机制会导致递归执行的更加低效,使用循环代替递归算法 ...

  3. 树:二叉树的非递归遍历算法

    二叉树的递归遍历 二叉树的递归遍历算法,写法很简单,比如说前序遍历树,如下: //前序遍历 void PreOrderTraverse(BiTree tree) {if (NULL != tree){ ...

  4. 二叉树的非递归遍历(统一的模板)

    二叉树的非递归遍历 前言 树的存储结构 先序遍历 先序的递归遍历 先序的非递归遍历 中序遍历 中序的递归遍历 中序遍历的非递归算法 后序遍历 后序的递归遍历 后序的非递归遍历 层次遍历 层次遍历获得每 ...

  5. c语言以顺序结构存储的二叉树的非递归遍历,C语言二叉树的非递归遍历实例分析...

    本文以实例形式讲述了C语言实现二叉树的非递归遍历方法.是数据结构与算法设计中常用的技巧.分享给大家供大家参考.具体方法如下: 先序遍历: void preOrder(Node *p) //非递归 { ...

  6. 6-9 二叉树的非递归遍历 (20 分)

    ** 6-9 二叉树的非递归遍历 (20 分) ** 本题要求用非递归的方法实现对给定二叉树的 3 种遍历. 函数接口定义: void InorderTraversal( BinTree BT ); ...

  7. C/C++ 二叉树的非递归遍历(前序、中序、后序非递归遍历)

     二叉树的非递归遍历C/C++实现:   非递归先序遍历代码: void PreOrderTraversal (struct tree* root) { //非递归先序遍历struct tree* t ...

  8. C语言实现二叉树的非递归遍历

    C语言实现二叉树的非递归遍历: 代码解释: 非递归前序遍历:1> 首先建立一个二维指针,用来存储每个结点的地址,定义栈顶指针top,初始值为-1,并将根结点存入栈中,top++:2> 进入 ...

  9. 二叉树的非递归遍历(C语言实现)

    上一篇讨论了二叉树的的递归遍历,这一次讨论二叉树的三种非递归遍历 二叉树的非递归遍历采用栈实现,首先给出二叉树和栈的定义 #define STACK_INIT_SIZE 100 #define STA ...

最新文章

  1. 【WWW2021】高效的非抽样知识图谱嵌入
  2. Dubbo点滴(1) SPI入门
  3. 【EventBus】事件通信框架 ( 订阅方法注册 | 注册 事件类型 - 订阅类 + 订阅方法 到指定集合 | 取消注册 数据准备 )
  4. 手机淘宝 521 性能优化项目揭秘
  5. CTF——Web——MD5漏洞
  6. 新编辑神器,可以在终端运行 Jupyter Notebook 了!
  7. 介绍Portable PDB
  8. 大数据胸_喂母乳会导致胸下垂?!你被这个谣言骗了多少年?
  9. div下图片自适应解决方法
  10. 百练4982 踩方格
  11. python 根据文件夹大小删除修改时间比较早的文件
  12. flex white-space: nowrap,撑大盒子问题
  13. Quartz.Net 使用
  14. 图像变形功能的应用: 在线修整发型
  15. Wix 3.0正式发布
  16. springboot指定属性返回_SpringBoot中属性赋值操作的实现
  17. 多个路由指向同一个页面_Flutter路由导航
  18. 某新闻App sign签名算法解析(一)
  19. Python图形处理
  20. |poj 3237|树链剖分|线段树|Tree

热门文章

  1. GitHub 中 Merge pull request 的 3 中选项说明
  2. pycharm导包错误
  3. Pytorch中多GPU训练指北
  4. 卷积神经网络(CNN)张量(图像)的尺寸和参数计算(深度学习)
  5. 合肥工业大学—SQL Server数据库实验四:数据库的分离和附加
  6. 使用Tensor Expression张量表达式处理算子
  7. 目标检测数据集The Object Detection Dataset
  8. YOLOV4各个创新功能模块技术分析(二)
  9. 2021年大数据Hadoop(九):HDFS的高级使用命令
  10. Python 判断当前数值的类型(比如x=10 获取x的类型)