二叉树的遍历
来源:互联网 发布:微信支付java案例demo 编辑:程序博客网 时间:2024/05/16 10:21
一、先定义二叉树的数据结构
typedef struct TreeNode *BinTree;struct TreeNode { ElementType data; BinTree left; BinTree right; };
二、基于DFS的递归遍历
1. 先序遍历(PreOrder)
void PreOrder(BinTree T){if(!T) return;Visit(T);PreOrder(T->left);PreOrder(T->right);}
2. 中序遍历(InOrder)
void InOrder(BinTree T){if(!T) return;InOrder(T->left);Visit(T);InOrder(T->right);}
3. 后序遍历(PostOrder)
void PostOrder(BinTree T){if(!T) return;InOrder(T->left);InOrder(T->right);Visit(T);}
Summarize: 这三种遍历过程,经过结点的路线是一样的,只是访问各结点的时机不同。
三、利用堆栈实现非递归遍历
借助堆栈实现实际上就是模拟递归函数调用时的入栈和出栈过程,先序遍历是结点第一次入栈即访问,然后分别对该结点的左右子树遍历;中序遍历是当结点出栈时,表明刚完成对该结点左子树的访问,这时访问该结点。
1. 先序非递归
1) 遇到一个结点,访问后入栈,并遍历其左子树;
2) 当左子树遍历完后,从栈顶弹出一个结点;
3) 按该结点的右指针遍历其右子树;
4) 当p为NULL且栈空时,整个遍历过程结束。
void PreOrder(BinTree T){stack<BinTree> S;BinTree p = T;while(p || !S.empty()){while(p){Visit(p);S.push(p);p = p->left;}if(!S.empty()){p = S.top();S.pop();p = p->right;}}}
2. 中序非递归
同先序基本一样,不同之处在于访问结点的时机,是在结点出栈后访问。
void InOrder(BinTree T){stack<BinTree> S;BinTree p = T;while(p || !S.empty()){while(p){S.push(p);p = p->left;}if(!S.empty()){p = S.top();Visit(p);S.pop();p = p->right;}}}
3. 后序非递归
与前两个非递归的过程不同,后序遍历必须在左右子树均访问后才访问根结点,关键是要确定什么时候右子树遍历结束。一种思路是在某一结点的左子树遍历完后将其再次入栈,等到再次出栈就说明其右子树已经遍历结束,这时候就可以访问该结点了。也就是说,在整个后序非递归过程中,每个结点出入栈两次,第一次出栈说明其左子树遍历完成,第二次出栈说明其右子树也遍历完成,而为了区分是第几次出栈,每个结点需要添加一个变量标记。
void postOrder(BinTree T){ if(!T) return; stack<BinTree> S; BinTree p = T; while(p || !S.empty()) { if(p){ S.push(p); p = p->left; } else{ p = S.top(); S.pop(); p->flag++; if(p->flag == 2){ Visit(p); p = NULL; } else{ S.push(p); p = p->right; } } }}
四、基于BFS的层序遍历
1. 层序遍历用队列实现,从根节点开始,首先将根节点入队,然后执行循环:结点出队并访问,左右结点入队,直到队列为空,形成按广度优先搜索的遍历方式。
基本过程:
1) 根节点入队;
2) 从队列中出队一个结点;
3) 访问该结点;
4) 如果该结点左右子结点非空,依次入队;
5) 队列为空,遍历结束。
void LevelOrder(BinTree T){ if(!T) return; queue<BinTree> Q; BinTree p = T; Q.push(p); while(!Q.empty()) { p = Q.front(); Visit(p); Q.pop(); if(p->left) Q.push(p->left); if(p->right) Q.push(p->right); }}
2. 有意思的是,基于层序遍历的思想也可以实现先序、中序和后序三种遍历。只要将队列改为栈,同时改变结点的的入栈顺序即可。
1) 先序:入栈顺序为右结点再左结点。
void LevelPreOrder(BinTree T){ if(!T) return; stack<BinTree> S; BinTree p = T; S.push(p); while(!S.empty()) { p = S.top(); Visit(p); S.pop(); if(p->right) S.push(p->right); if(p->left) S.push(p->left); }}
2) 中序:为了知道左右子树什么时候遍历结束,结点需要出入栈两次,第一次出栈后在左右结点间再次入栈,第二次出栈时即可访问该结点。
入栈顺序:右结点->当前结点->左结点
void LevelInOrder(BinTree T){ if(!T) return; stack<BinTree> S; BinTree p = T; S.push(p); while(!S.empty()) { p = S.top(); p->flag++; S.pop(); if(p->flag == 2){ Visit(p); } else{ if(p->right) S.push(p->right); S.push(p); if(p->left) S.push(p->left); } }}
3) 后序:与中序类似,结点第一次出栈后在左右结点之前再次入栈,第二次出栈后访问。入栈顺序:当前结点->右结点->左结点
void LevelPostOrder(BinTree T){ if(!T) return; stack<BinTree> S; BinTree p = T; S.push(p); while(!S.empty()) { p = S.top(); p->flag++; S.pop(); if(p->flag == 2){ Visit(p); } else{ S.push(p); if(p->right) S.push(p->right); if(p->left) S.push(p->left); } }}
0 0
- 二叉树的遍历
- 二叉树的遍历
- 二叉树的遍历
- 二叉树的遍历
- 二叉树的遍历
- 二叉树的遍历
- 二叉树的遍历
- 二叉树的遍历
- 二叉树的遍历
- 二叉树的遍历
- 二叉树的遍历
- 二叉树的遍历
- 二叉树的遍历
- 二叉树的遍历
- 二叉树的遍历
- 二叉树的遍历
- 二叉树的遍历
- 二叉树的遍历
- CSS样式优先级
- 写出你觉得好用的Eclipse 插件
- 欢迎使用CSDN-markdown编辑器
- Android笔记——GridLayout布局
- 缓存服务器
- 二叉树的遍历
- android两种方法操作Sqlite数据库
- UESTC 1017 王之困惑 找规律、分类讨论
- 杭电ACM 1008 1009
- 缓存Memcached以及缓存策略
- UESTC 1013 我的魔法栈 贪心法
- c++ template 的traits技术
- linux之cut用法
- 算法马拉松8(差和问题)