二叉树的建立和深度优先遍历
来源:互联网 发布:茶叶网络营销策划书 编辑:程序博客网 时间:2024/05/20 11:24
一、二叉树的ADT
首先我们定义二叉树的结点Node
struct Node{int data;Node* left;Node* right;Node(int _data):data(_data),left(0),right(0){}bool isLeaf() {return left==NULL && right==NULL;}};
然后我们定义二叉树的抽象类型:要注意的是二叉树只需要一个成员变量Node* root指向树根。如果root为空指针,则此二叉树为空树
typedef stack<Node*> Stack;typedef queue<Node*> Queue;class BinaryTree{private://what we only need is a root nodeNode* root;public:BinaryTree():root(0){}BinaryTree(Node* _root):root(_root){}~BinaryTree(){destroy(root);}void destroy(Node* n) {/*按照后序遍历的思想,先递归析构左右子树*/}void iterate_vlr(Node* v);void iterate_vlr() {iterate_vlr(getTree());}void iterate_lvr(Node* v);void iterate_lvr() {iterate_lvr(getTree());}void iterate_lrv(Node* v);void iterate_lrv() {iterate_lrv(getTree());}void queue_layer(Node* v);void queue_layer() {queue_layer(getTree());}void stack_vlr(Node* v); void stack_vlr() {stack_vlr(getTree());}void stack_lvr(Node* v);void stack_lvr() {stack_lvr(getTree());}void stack_lrv(Node* v);void stack_lrv() {stack_lrv(getTree());}bool isEmpty() {return root==0;}Node* getTree(){return root;}};
二、二叉树的深度优先递归遍历
这个很简单,cout加在哪里就是什么遍历
void BinaryTree::iterate_vlr(Node* v){if (v==NULL){//cout<<"the tree is empty"<<endl;return;}cout<<(v->data)<<' ';iterate_vlr(v->left);iterate_vlr(v->right);}
三、二叉树的深度非递归遍历
要想搞清非递归遍历背后的数学规律,我们有必要研究一下二叉树遍历的函数帧(stack frame)。
我们先忽略cout输出,只关注函数栈的变化
以如图二叉树为例:
函数帧应当如图所示:
从函数帧本身来说,函数每发生一次递归调用,栈就会升高一个单位;每接受一次返回,栈就会降低一个单位。因此每发生一次调用,栈必然或升或降一个单位,既不会与上一次调用持平,也不会升降更多。
从二叉树来说,每个非空结点都会发出两次调用,因此必然接受两次返回。
现在我们把栈顶用曲线连接起来,我们定义:
“单调递增点”就是指由递增产生的,并且继续递增的点,“单调递增边沿”就是由相邻的这些点组成的边沿。
同理也可以定义“单调递减边沿”。
结合cout出现的位置,我们发现:
i. 后序遍历的结果出现在单调递减边沿。
ii. 前序遍历的结果出现在单调递增边沿。
iii. 中序遍历的结果出现在“波谷”。
要想把这些发现转化成代码,还需要研究两种边沿和波谷的产生条件。
i. 有且只有栈的push操作才能产生递增边沿。对于二叉树来讲,(a)沿着左子树深搜以及(b)第一次到达右子树的根结点,这两种情况能引发入栈。
ii. 有且仅有栈的pop操作才能产生递减边沿。对于二叉树来讲,(a)左右子树都为空以及(b)左右子树都完成访问,这两种情况能引发出栈。
iii. 对于二叉树来说,(a)访问到叶子节点会产生波谷。同时,(b)如果某时刻一个节点的左子树已经访问完毕,但是还没有访问右子树,那么这个节点此时也在波谷。
void BinaryTree::stack_traverse(Node* v){Node* now = v;Node* tmp = 0; //tmp是用来记忆右子树是否被访问过的Stack s;while (now != 0 || !s.empty()){while (now != 0) //这个循环是用来深搜的{s.push(now);/*cout在这里就是先序遍历*/now = now->left;}now = s.top();if (now->right != tmp || now->right==0){/*cout在这里就是中序遍历*/}if (now->right==0 || now->right == tmp){tmp = now;s.pop();/*cout在这里就是中序遍历*/now = 0; //now=0确保执行下一轮主循环的时候,跳过深搜直接now=top}else now = now->right;}cout<<endl;}
这里我想解释一下两个if的条件为什么要这么写
第一个if很好解释:now->right != tmp就是右子树还没访问 now->right==0就是右子树为空。这是中序遍历(波谷)的条件
第二个if:如果now->right==0,那么为了模拟递归,我至少要做三件事:1. 记忆当前结点,代表当前结点已经被访问; 2.弹栈; 3.让now==0,目的是确保执行下一轮主循环的时候,跳过深搜直接now=top
附: 二叉树的广度层遍历:
inline bool visit(Node* T){if (T){printf("%d ", T->data);return true;}else return false;}void BinaryTree::queue_layer(Node* v){Queue q;Node* n = v;if (visit(n)){q.push(n);//push root}while (!q.empty()){n = q.front();q.pop(); //pop this layerif (visit(n->left))q.push(n->left); //push next layerif (visit(n->right))q.push(n->right); //push next layer}cout<<endl;}
- 二叉树的建立和深度优先遍历
- 二叉树的深度优先遍历和深度优先遍历
- 二叉树的深度优先遍历和广度优先遍历
- 二叉树的深度优先遍历和广度优先遍历
- 二叉树的深度优先遍历和广度优先遍历
- 二叉树的深度优先遍历和广度优先遍历
- 二叉树的深度优先遍历和广度优先遍历
- 二叉树的深度优先遍历和广度优先遍历
- 二叉树的广度优先遍历和深度优先遍历
- 二叉树的深度优先遍历和广度优先遍历
- 二叉树的深度优先遍历和广度优先遍历
- 二叉树的深度优先遍历和广度优先遍历
- 二叉树的深度优先遍历和广度优先遍历
- 二叉树的深度优先遍历和广度优先遍历
- 二叉树的深度优先遍历和广度优先遍历
- 二叉树的深度优先遍历和广度优先遍历
- 二叉树的深度优先遍历和广度优先遍历
- 二叉树的深度优先遍历和广度优先遍历
- 安卓手机:你的手机没有安装google play服务,因此无法运行此应用
- 基于solr实现hbase的二级索引
- ArcGIS中各种合并要素(Union、Merge、Append、Dissolve)的异同点分析
- S2SH简单整合
- LeetCode:Plus One
- 二叉树的建立和深度优先遍历
- DOM4J的使用的好文章(转)
- HTML5规范尘埃落定,5个开发工具推荐
- 如何获取Android唯一标识(唯一序列号)
- cvLoadImage()的调用参数设置
- windows7 配置php开发环境
- iPhone消息推送机制实现与探讨
- 使用宏函数置换两个数的方法
- Cocco2D问答