二叉树前序、中序、后序遍历的非递归写法
来源:互联网 发布:linux w 编辑:程序博客网 时间:2024/05/16 18:23
由于考研需要考到这个知识,因此写了代码实现了下,顺便整理下.
前序和中序遍历的非递归写法都比较好实现,后序遍历稍微复杂一些.
数据结构定义:
struct Node{ char c; pNode lchild, rchild; Node(char c, pNode lchild = nullptr, pNode rchild = nullptr) : c(c), lchild(lchild), rchild(rchild) {}};
二叉树形态:
A / \ B C / \ / \ D E F G / \ H I
前序遍历:
先根遍历,拿到一个节点的指针,先判断是否为空,不为空就先访问该结点,然后直接进栈,接着遍历左子树;为空则要从栈中弹出一个节点来,这个时候弹出的结点就是其父亲,然后访问其父亲的右子树,直到当前节点为空且栈为空时,算法结束.
void preVisitStack(pNode root){ stack<pNode> st; pNode p = root; while (p || !st.empty()) { if (p) { visit(p); st.push(p); p = p->lchild; } else { p = st.top(); st.pop(); p = p->rchild; } } cout << endl;}
中序遍历:
和前序遍历一样,只不过在访问节点的时候顺序不一样,访问节点的时机是从栈中弹出元素时访问,如果从栈中弹出元素,就意味着当前节点父亲的左子树已经遍历完成,这时候访问父亲,就是中序遍历.
void midVisitStack(pNode root){ stack<pNode> st; pNode p = root; while (p || !st.empty()) { if (p) { st.push(p); p = p->lchild; } else { p = st.top(); visit(p); st.pop(); p = p->rchild; } } cout << endl;}
后序遍历:
后续遍历就不一样了,首先肯定是先访问左子树,把父亲节点保存于栈中,问题是当元素从栈中弹出的时候,我们无法判断这个时候是该访问其右子树还是访问父亲节点,于是我们就需要一个标记,当访问左子树时我们把父亲节点的标记设为1,表示下一步如果弹出该节点,就访问其右子树;弹出一个节点时,我们要判断该节点的标记,如果是1,则访问其右子树,并把该节点的标记设置成2,表示下一步就访问该节点,然后把该节点继续入栈,如果是2,那么表示访问该节点,访问并且丢弃该节点.
为了不继续添加新的数据结构,我是用了STL中的pair来封装节点与标记.
void backVisitStack(pNode root){ stack<pair<pNode, int> > st; pNode p = root; while (p || !st.empty()) { if (p) { st.push(make_pair(p, 1)); p = p->lchild; } else { auto now = st.top(); st.pop(); if (now.second == 1) { st.push(make_pair(now.first, 2)); p = now.first->rchild; } else visit(now.first); } } cout << endl;}
完整测试代码:
#include <bits/stdc++.h>using namespace std;typedef struct Node *pNode;struct Node{ char c; pNode lchild, rchild; Node(char c, pNode lchild = nullptr, pNode rchild = nullptr) : c(c), lchild(lchild), rchild(rchild) {}};pNode build(){ /* A / \ B C / \ / \ D E F G / \ H I */ pNode root = new Node('A'); root->lchild = new Node('B'); root->rchild = new Node('C'); root->lchild->lchild = new Node('D'); root->lchild->rchild = new Node('E'); root->rchild->lchild = new Node('F'); root->rchild->rchild = new Node('G'); root->rchild->lchild->lchild = new Node('H'); root->rchild->lchild->rchild = new Node('I'); return root;}void visit(pNode x){ cout << x->c << " ";}void preVisitStack(pNode root){ stack<pNode> st; pNode p = root; while (p || !st.empty()) { if (p) { visit(p); st.push(p); p = p->lchild; } else { p = st.top(); st.pop(); p = p->rchild; } } cout << endl;}void midVisitStack(pNode root){ stack<pNode> st; pNode p = root; while (p || !st.empty()) { if (p) { st.push(p); p = p->lchild; } else { p = st.top(); visit(p); st.pop(); p = p->rchild; } } cout << endl;}void backVisitStack(pNode root){ stack<pair<pNode, int> > st; pNode p = root; while (p || !st.empty()) { if (p) { st.push(make_pair(p, 1)); p = p->lchild; } else { auto now = st.top(); st.pop(); if (now.second == 1) { st.push(make_pair(now.first, 2)); p = now.first->rchild; } else visit(now.first); } } cout << endl;}int main(){ pNode root = build(); preVisitStack(root); midVisitStack(root); backVisitStack(root);}
测试结果:
依次为前序、中序、后序遍历的结果.
A B D E C F H I G
D B E A H F I C G
D E B H I F G C A
阅读全文
0 0
- 二叉树前序、中序、后序遍历非递归写法
- 二叉树前序、中序、后序遍历非递归写法
- 二叉树前序、中序、后序遍历非递归写法的透彻解析
- 二叉树前序、中序、后序遍历非递归写法的透彻解析
- 二叉树前序、中序、后序遍历非递归写法的透彻解析
- 二叉树前序、中序、后序遍历非递归写法的透彻解析
- 二叉树前序、中序、后序遍历非递归写法的透彻解析
- 二叉树前序、中序、后序遍历非递归写法的透彻解析
- 二叉树前序、中序、后序遍历非递归写法的透彻解析
- 二叉树前序、中序、后序遍历非递归写法的透彻解析
- 二叉树前序、中序、后序遍历非递归写法的透彻解析
- 二叉树前序、中序、后序遍历非递归写法的透彻解析
- 二叉树前序、中序、后序遍历非递归写法的透彻解析
- 二叉树前序、中序、后序遍历非递归写法的透彻解析
- 二叉树前序、中序、后序遍历非递归写法的透彻解析
- 二叉树前序、中序、后序遍历的非递归写法
- 二叉树前序、中序、后序遍历非递归写法的透彻解析
- 二叉树前序、中序、后序遍历非递归写法的透彻解析
- 顺序串的算法库(有点自己的想法)
- 基于支付系统场景的微服务架构的分布式事务解决方案
- a标签取消默认的href链接跳转
- matlab——安装fielldtrip工具包
- 原生JavaScript事件详解
- 二叉树前序、中序、后序遍历的非递归写法
- webpack入门使用
- CheckBox、RadioButton只显示图片,不显示文字,并且没有文字区域,只有图片区域
- PAT——1032. 挖掘机技术哪家强
- 提升树GBDT详解
- 看清OMA DRM文件的本质
- Java动态代理与Cglib
- 蓝桥杯试题: 熊怪吃核桃
- Cocos2dx杂记:PhysicsEditor 对应cocos2dx 3.x的接口封装