二叉树的创建(先序创建的)及先序遍历 中序遍历 后序遍历的递归和非递归实现
来源:互联网 发布:网络工程学院 编辑:程序博客网 时间:2024/05/16 07:22
1. 首先是关于二树结点的设计
typedefstruct TreeNode *PtrToNode;typedef PtrToNode BinTree;struct TreeNode{ char data;//结点数据,假设是字符 BinTree left; // 指向左子树 BinTree right; // 指向右子树};
2. 其次是二叉树创建的模拟
根据先序次序输入二叉树的结点,从而创建一个二叉树(‘-’字符表示树空,当然也可以是其他字符,比如空格);
例如一棵树结构如下,其输入次序为:abd--fe---cg-h--i--
二叉树根据键盘输入字符的创建模拟函数
BinTree binTreeCreate(){ BinTree t; char temp; scanf("%c", &temp); if ('-' == temp) t = NULL; else { t = (BinTree)malloc(sizeof(struct TreeNode)); t->data = temp; t->left = binTreeCreate(t->left); t->right = binTreeCreate(t->right); } return t;}
3. 递归实现的三种遍历(先序 中序 后序)
3.1 先序遍历二叉树的操作定义为:
若二叉树为空,则空操作;否则:
(1) 访问根结点
(2) 先序遍历左子树
(3) 先序遍历右子树
void binTreePreOrderTraversal(BinTree T){ if(T) { printf("%c ", T->data); binTreePreOrderTraversal(T->left); binTreePreOrderTraversal(T->right); }}
3.2 中序遍历二叉树的操作定义为:
若二叉树为空,则空操作;否则:
(1) 中序遍历左子树
(2) 访问根结点
(3) 中序遍历右子树
void binTreeInOrderTraversal(BinTree T){ if(T) { binTreeInOrderTraversal(T->left); printf("%c ", T->data); binTreeInOrderTraversal(T->right); }}
3.3 后序遍历二叉树的操作定义为:
若二叉树为空,则空操作;否则:
(1) 中序遍历左子树
(2) 中序遍历右子树
(3) 访问根结点
void binTreePostOrderTraversal(BinTree T){ if(T) { binTreePostOrderTraversal(T->left); binTreePostOrderTraversal(T->right); printf("%c ", T->data); }}
4. 非递归实现的三种遍历(先序 中序 后序)
思路是这样的:
先序、中序和后序遍历过程: 遍历过程中经过结点的路线一样,只是访问各结点的时机不同。
下图在从入口到出口的曲线上用三种符号分别标记出了先序、中序和后序访问各结点的时刻。
二叉树的非递归遍历算法实现的基本思路:使用堆栈,依据各结点的访问时序实现即可
4.1 先序遍历非递归思路:
遇到一个结点(第一次遇到),访问它,再把它压栈,并去遍历它的左子树;
当左子树遍历结束后,从栈顶弹出这个结点;
然后按其右指针再去先序遍历该结点的右子树。
void binTreePreOrderTraversal(BinTree T){ //创建并初始化堆栈S Stack s = CreateStack(MAXSIZE); while (T || !IsEmpty(s)) // 循环结点的条件是T空且栈空 { while (T) { printf("%c ", T->data); Push(s, T); T = T->left; } if (!IsEmpty(s)) { T = Pop(s); T = T->right; } }}
4.2 中序遍历非递归思路:
遇到一个结点,就把它压栈,并去遍历它的左子树;
当左子树遍历结束后,从栈顶弹出这个结点(第二次遇到该结点)并访问它;
然后按其右指针再去中序遍历该结点的右子树。
void binTreeInOrderTraversal(BinTree T){ // 创建并初始化堆栈S Stack s = CreateStack(MAXSIZE); while (T || !IsEmpty(s)) { while (T) { Push(s, T); T = T->left; } if (!IsEmpty(s)) { T = Pop(s); printf("%c ", T->data); T = T->right; } } }
4.3 后序遍历非递归思路:
遇到一个结点,就把它压栈(第一次遇到该结点),并去遍历它的左子树;
当左子树遍历结束后,从栈顶取出这个结点的值 (第二次遇到该结点),并不进行弹栈处理;
然后按其右指针再去后序遍历该结点的右子树;
当其右子树遍历结点后,从栈顶取出该值访问并弹栈;
由时序图可以看出每个结点都可以看作第三次才访问的,即其左右子树都已经进行过遍历,而无论其左右子树有无;
那么在树结点中增加一个flag字段记录结点访问的时序(第几次遇到该结点),很明显后序是第三次,那么可以这么设计:
首先树中每个结点的flag字段默认值为0,将结点首次压栈时,将其flag字段值+1(表明即将遍历其左子树);
依次遍历左子树,当左子树遍历结束后,退出小循环,对栈顶元素进行处理;
若栈顶元素的flag字段值为1,表明其左子树已经遍历完,然后按其右指针再去后序遍历该结点的右子树,flag字段值再+1(表明即将遍历其右子树),此时栈顶元素,并不出栈;
若栈顶元素的flag字段值为2,表明其右子树已经遍历完,那么访问该结点并将其出栈,再对栈中其它元素进行处理。
这里我偷懒就在原结构体上进行了添加字段
struct TreeNode{ char data;//结点数据 BinTree left; // 指向左子树 BinTree right; // 指向右子树 int flag; //访问标志,方便后序非递归遍历};
代码如下:
void binTreePostOrderTraversal(BinTree T){ //创建并初始化堆栈S Stack s = CreateStack(MAXSIZE); while (T || !IsEmpty(s)) { while (T && T->flag==0) { T->flag++;//该结点第一次访问,将其入栈 Push(s, T); T = T->left; } if (!IsEmpty(s)) { T = Top(s); if (T->flag ==2)//后序遍历,每个结点基本上可以看做第三次遇到才访问 { T = Pop(s); printf("%c ", T->data); T = Top(s); } else { T->flag++;//该结点第二次遇到,此时结点在栈中,但不出栈 T = T->right; // 处理其右子树 } } }}
- 二叉树的创建(先序创建的)及先序遍历 中序遍历 后序遍历的递归和非递归实现
- 二叉树的创建和先序,中序,后序,递归,非递归遍历
- 二叉树的先序创建,先序,中序,后序的递归与非递归遍历,层次遍历,叶子结点数及树的深度
- 二叉树的先序、中序、后序递归遍历和非递归遍历
- 二叉树的创建 先序 中序 后续 递归和非递归遍历
- 二叉树的先序、中序、后序遍历的递归和非递归实现
- 二叉树的创建及递归的先,中,后序遍历
- 二叉树的递归创建,先序(中序、后序)递归遍历二叉树
- 二叉树的先序递归创建和遍历
- 二叉树递归的创建及三种遍历(先序、中序、后序)
- 二叉树的先序、中序、后序、层序递归及非递归遍历
- 二叉树的创建与先、中、后序遍历递归实现
- 建立二叉树,实现二叉树的先序遍历、中序和后序遍历的非递归算法
- 二叉树的先序、中序、后序的递归及非递归实现,以及层次遍历的实现:
- 二叉树的创建,先序、中序、后序遍历的递归实现以及层序遍历
- 二叉树T 的先序遍历、中序遍历、后序遍历(递归实现)
- 二叉树的先序、中序、后续遍历的递归和非递归实现
- 二叉树(一) 先序遍历、中序遍历、后续遍历、层次遍历的递归与非递归实现
- 浅拷贝、深拷贝以及拷贝构造函数
- javascript常用数组算法总结
- 顺序栈的实现
- 【Ogre引擎架构】 第七讲 粒子系统-爆破特效
- 使用System.Windows.Forms.Application.DoEvents实时更新画面
- 二叉树的创建(先序创建的)及先序遍历 中序遍历 后序遍历的递归和非递归实现
- NYOJ-833解题报告
- 关于((ch = getchar()) != EOF),ch声明为整型的问题
- 抽象类与接口
- 多线程之GCD
- 站上历史浪潮的计算机(一)
- 黑马程序员——java基础之Set集合
- IplImage结构及与其相关的读写函数
- 扫雷代码