上期文章: 数据结构 | 树与二叉树

参考教材:《数据结构》,刘大有

编程语言: C++


目录

(一)二叉树的存储结构

(二)二叉树的遍历

先根遍历非递归算法

中根遍历非递归算法

后根遍历非递归算法


(一)二叉树的存储结构

二叉树在计算机中具有顺序存储和链式存储两种存储方式。在本文所讨论的算法中,二叉树均是采用二叉链表的存储方式

struct Node{Node *left;Node *right;char data;Node():left(nullptr),right(nullptr),data('#'){}
};

其中left为指向该结点左儿子的指针,right为指向该结点右儿子的指针

(二)二叉树的遍历

先根遍历非递归算法

先根遍历的顺序为①访问根、②遍历左子树、③遍历右子树

为了实现先根遍历的非递归算法,我们需要引进一个辅助堆栈,栈的元素为Node *类型

//栈
class Stack{
public:Stack():top(0){for(int i=0;i<s_size;i++){s[i]=nullptr;}}//入栈void push(Node *p){if(top<s_size){s[top]=p;top++;}else{cout<<"Stack overflow!"<<endl;return;}}//出栈Node *pop(){if(top==0){return nullptr;}else{top--;return s[top];}}bool isEmpty(){if(top==0)return true;elsereturn false;}
private:const int s_size=20;Node *s[s_size];int top;
};

先根遍历的非递归算法较为简单,用自然语言描述就是:

  1. 根结点入栈
  2. 判断,如果栈为空则结束算法;否则,当栈不为空时:弹栈,访问该结点;如果该结点右儿子存在则入栈;如果该结点左儿子存在则入栈
  3. 返回第2步
/*先根遍历非递归算法*/
void nPreOrder(Node * root){if(root == nullptr){return;}Stack s;Node *p=root;//根节点入栈s.push(p);//栈不为空时:while(!s.isEmpty()){//弹栈:p=s.pop();cout<<p->data;//右儿子入栈:if(p->right!=nullptr){s.push(p->right);}//左儿子入栈:if(p->left!=nullptr){s.push(p->left);}}return;
}

以下面这棵树为例

算法执行过程中,栈的变化情况如下,最终输出的先根序列为ABDFCE:


中根遍历非递归算法

中根遍历的顺序为①遍历左子树、②访问根、③遍历右子树

中根遍历的非递归算法也需要引入辅助堆栈,栈的结构与上面先根遍历非递归算法用到的栈Stack相同

中根遍历非递归算法思想:

  1. 令p=root
  2. 判断,如果栈不为空或p不等于nullptr,执行下一步;否则算法结束
  3. 当p不等于nullptr(空指针)时,让p结点入栈;如果p结点的左儿子存在,也让其左儿子入栈;如果p结点左儿子的左儿子存在,依然让其左儿子的左儿子入栈......以此类推,直到p的某一个后裔结点不存在左儿子时,执行下一步
  4. 弹出栈顶元素(这时候栈一定不为空),访问该结点,把该结点的右儿子的地址赋值给p;返回第2步
/*中根遍历非递归算法*/
void nInOrder(Node * root){if(root==nullptr){return;}Stack s;Node *p=root;while( (!s.isEmpty()) || (p!=nullptr) ){while(p!=nullptr){s.push(p);p=p->left;}p=s.pop();cout<<p->data;p=p->right;}
}

以下面这棵树为例

算法执行过程中,栈的变化情况如下,最终输出的中根序列为BFDAEC:


后根遍历非递归算法

后根遍历的顺序为①遍历左子树、②遍历右子树、③访问根

后根遍历的非递归算法依然需要引入辅助堆栈。但是注意,这里栈的结构与上面的栈结构不同,这里栈的元素为包含Node *和int 类型的结构体

//栈2元素的结构
struct NodeOfStack{Node *pnode;int times;//入栈次数NodeOfStack():pnode(nullptr),times(0){}
};

其中pnode为Node *类型的指针,times记录了该结点入栈的次数 ,times的值可取0,1,2

栈2的定义如下:

//栈2
class Stack2{
public:Stack2():top(0){for(int i=0;i<s_size;i++){s[i].pnode=nullptr;s[i].times=0;}}//入栈void push(Node *p,int t){if(top<s_size){s[top].pnode=p;s[top].times=t;top++;}else{cout<<"Stack overflow!"<<endl;return;}}//出栈NodeOfStack pop(){if(top>0){top--;return s[top];}}bool isEmpty(){if(top==0)return true;elsereturn false;}
private:const int s_size=20;NodeOfStack s[20];int top;
};

后根遍历的非递归算法:

  1. (root,0)入栈
  2. 判断,如果栈为空,结束算法;否则,栈不为空时:弹栈,记为(p,times)。若times==0,(p,1)入栈,如果p的左儿子存在则(p->left,0)也压入栈。若times==1,(p,2)入栈,如果p的右儿子存在则(p->right,0)也压入栈。若times==2,访问p结点
  3. 返回第2步

/*后根遍历非递归算法*/
void nPostOrder(Node * root){if(root==nullptr){return;}Stack2 s;s.push(root,0);while(!s.isEmpty()){NodeOfStack nos=s.pop();//中间变量,存储每一次栈弹出的数据Node *p=nos.pnode;if(nos.times==0){s.push(nos.pnode,1);if(p->left!=nullptr){s.push(p->left,0);}}else if(nos.times==1){s.push(nos.pnode,2);if(p->right!=nullptr){s.push(p->right,0);}}else if(nos.times==2){cout<<p->data;}}
}

以下面这棵树为例

最终输出的后根序列为FDBECA

数据结构 | 二叉树 先根、中根、后根遍历的非递归算法相关推荐

  1. 二叉树先、中、后遍历递归+非递归

    文章目录 前言 思路 设计思想 非递归前序遍历的思路 非递归中序遍历的思路 非递归后序遍历的思路 层序遍历的思路 完整代码 MyBinaryTree.h MyBinaryTree.cpp Main.c ...

  2. python数据结构二叉树的前序,中序,后续遍历与推导

    根据先序中序求后续 其余同理,多画图就理解了

  3. DS007-二叉树-顺序表表示法-先根-中根-后根遍历

    本篇介绍二叉树的顺序表表示法,及其先.中.后根遍历. 以下面这棵二叉树为例. 对应的顺序存储结构为: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 a b c \0 ...

  4. DS007-二叉树-伪指针表示法-先根-中根-后根遍历

    本篇介绍二叉树的伪指针表示法,及其先.中.后根遍历. 以下面这棵二叉树为例. 对应的伪指针存储结构为: 整体是一个顺序表,每个元素是一个结构体,包含本身元素,左孩子的下标,右孩子的下标. 也可以包含双 ...

  5. DS007-二叉树-二叉链表表示法-先根-中根-后根遍历

    本篇介绍二叉树的二叉链表表示法,及其先.中.后根遍历. 以下面这棵二叉树为例. #include "stdafx.h"#include<iostream> using ...

  6. 数据结构----二叉树叶子结点到根节点的高度计算

    数据结构----二叉树叶子结点到根节点的高度计算 代码: #include<stdio.h> #include<stdlib.h> typedef struct bstTree ...

  7. 二叉树的前,中,后序遍历(思路分析) [Java][数据结构]

    二叉树的前,中,后序遍历(思路分析) 前序遍历: 先输出父节点, 再遍历左子树和右子树 中序遍历: 先遍历左子树, 再输出父节点,再遍历右子树 后序遍历: 先遍历左子树,再遍历右子树,最后输出父节点 ...

  8. 二叉树前中后序遍历的非递归实现以及层次遍历、zig-zag型遍历详解

    前言 二叉树的遍历是一个比较常见的问题,递归实现二叉树的前中后序遍历比较简单,但非递归实现二叉树的前中后序遍历相对有难度.这篇博客将详述如何使用非递归的方式实现二叉树的前中后序遍历,在进行理论描述的同 ...

  9. [转载]二叉树先序、中序、后序三种遍历的非递归算法

    本贴给出二叉树先序.中序.后序三种遍历的非递归算法,此三个算法可视为标准算法. 1.先序遍历非递归算法 #define maxsize 100 typedef struct { Bitree Elem ...

最新文章

  1. 面向过程(结构化)分析方法与面向对象分析方法的区别
  2. 7 开机启动文件路径_为什么当我登录的时候,总有一些文件会被打开
  3. #中delay函数_ECBM系列教程3:闪烁灯——delay函数的用法。
  4. mysql之库操作_创建用户_修改用户权限_修改用户密码
  5. 网页html转为pdf,html页面转换成PDF文件
  6. 1000个摄像头的网络怎么搭建?为什么500个就卡的不行?
  7. 项目怎么导入mui_Vue项目MUI的使用
  8. 用条件变量实现事件等待器的正确与错误做法
  9. java编辑双层pdf文件,双层PDF制作系统
  10. 分享两种证件照换背景方法,轻松把照片底色变白
  11. 2022软考高项十大领域知识整理(四)-人力资源管理、干系人管理、采购管理
  12. VB编程:SelectCase多分支选择结构实例测试生肖运势-13
  13. 多元微积分_旋度2.旋度公式推导
  14. 《白帽子讲Web安全 》 随手记(一)
  15. mpu6050六轴传感器msp430驱动程序
  16. 华为cpe虚拟服务器,华为5G CPE Pro:让你不用换手机就能体验5G网络
  17. gradle linux配置环境变量配置文件,gradle init.gradle的文件配置 使用
  18. 【Python爬虫】Python网络爬虫案例:维基百科
  19. ASP.NET 基础(7)
  20. 普通青年VS文艺青年VS2B青年,爆笑语录!

热门文章

  1. c语言课程设计自我评价,学生成长卡,个人表现,自评
  2. 【解救Ros】CLB的Ros小车imu校正,角速度校正,线速度校正过程
  3. 搭建qnx开发环境,虚拟qnx系统+虚拟win7系统+QNX Momentics IDE 4.6
  4. 短信验证码常见漏洞总结
  5. SQL Server 修改表,不允许保存更改【解决办法】
  6. 状态模式(状态变化)
  7. 抢红包小程序(Java、头歌实验)
  8. ROS中的roslaunch命令和launch文件(ROS入门学习笔记四)
  9. java wap访问网页_在PC使用Chrome访问wap网页
  10. 使用putty连接并上传和下载文件到linux服务器