树的遍历
来源:互联网 发布:c 数组 编辑:程序博客网 时间:2024/05/20 04:26
(d1)先序遍历,(学会利用之前学的算法和理论),按照某种次序访问各节点,每个节点被访问恰好一次。先序(V,L,R),中序(L,V,R),后序(L,R,V),层次(自上而下,先左后右)。
Ø 递归实现:
template <typename T,typename VST>void traverse(BinNodePosi(T) x,VST &visit){ if(!x) return; visit(x->data); //访问 traverse(x->lChild,visit);//访问左子树 traverse(x->rChild,visit);//访问右子树}
时间复杂度为T(n)=O(1)+T(a)+T(n-a-1)=O(n);渐进线性复杂度。
Ø 递归→迭代:(尾递归,递归调用出现在递归实例的底部)
template <typename T,typename VST>void travPre_I1(BinNodePosi(T) x,VST & visit){ stack <BinNodePosi(T)> S; if(x) S.push(x); //将根节点入栈 while(!S.empty()) { x=S.pop();visit(x->data); //节点出栈,并访问 if(HasRChild(*x)) S.push(x->rChild); //右孩子先入栈 if(HasLChild(*x)) S.push(x->lChild);//左孩子后入栈 } }
Ø 迭代方法2:一直访问左节点
template <typename T,typename VST)static void visitAlongLeftBranch(BinNodePosi(T) x, VST &visit,stack<BinNodePosi(T)> &S){BinNodePosi(T) x;VST &visit;stack < BinNodePosi(T)> &s) while(x){ visit(x->data); //访问节点 S.push(x->rChild); //将右孩子入栈 x=x->lChild; //沿着左侧链下行 }}template <typename T,typename VST) void travPre_I2(BinNodePosi(T) x,VSRT & visit){ stack <BinNodePosi(T)> S; while(true){ visitAlongLeftBranch(x,visit,S);//调用函数,先入后出 if(S.empty()) break; //栈空即退出 x=S.pop(); //弹出下一子树的根 }}
(d2)中序遍历
Ø 首先,可以用递归的方法
template <typename T,typename VST>void traverse(BinNodePosi(T) x,VST &visit){ if(!x) return; traverse(x->lChild,visit);//访问左子树 visit(x->data); //访问根节点 traverse(x->rChild,visit)};<span style="font-family: Arial, Helvetica, sans-serif;">//访问右子树</span>
但是复杂度O(n)是我们不能接受的,所以需要进行修改。
Ø 迭代实现
体现在逆序性,首先访问的是最左侧分支的节点,然后逐一访问右子树。
template <typename T>static void goAlongLeftBranch(BinNodePosi(T) x,stack<BinNodePosi(T)> S){ while(x){ S.push(x);//将左侧子树入栈 x=x->lChild };} template <typename T,typename V>void travIn_I1(BinNodePosi(T) x,VST &visit){ stack <BinNodePosi(T)> S; while(x) { goAlongLeftBranch(x,S); if(S.empty()) break; x=S.pop(); //直接将遍历之后的左子树pop处理 visit(x->data);//直接访问 x=x->rChild; //进入到右孩子、右子树 }}
时间复杂度是O(n)
Ø 中序遍历的直接后继succ():
如果有右子树,则是右子树中的最左节点;否则,是当前节点包含左子树最低最先
template <typename T>BinNodePosi(T) BinNode<T>::succ(){ BinNodePosi(T) s=this; if(rChild) {//若有右孩子,则直接后继必在右子树中 s=rChild; while(HasLChild(*s)) s=s->lChild; //右子树的最小左子树 }else {//否则后继应该是“将当前节点包含于其左子树中的最低祖先” while(IsRChild(*s)) s=s->parent;//你想沿有分支进行查找,向左上方移动 s=s->parent; //最后再朝右上移动一步,则是后继 } return s;//有可能是NULL}
(d3)后序遍历
Ø 直接递归
template <typename T,typename VST>void traverse(BinNodePosi(T) x,VST &visit){ if(!x) return; traverse(x->lChild,visit); //左子树 traverse(x->rChild,visit);//右子树 visit(x->data);}
Ø 迭代使用?怎样使用呢?首先不是尾递归,解决方法是找到第一个被访
问的节点,将其祖先其右兄弟用栈保存。
尽可能的在左节点。
template <typename T>static void gotoHLVFL(stack<BinNodePosi(T)> &S){ while(BinNodePosi(T) x=S.top()) if(HasLChild(*x))//如果左孩子又有右孩子,先push右push左 { if(HashRChild(*x)) S.push(x->rChild); S.push(x->lChild); }else S.push(x->rChild); S.pop();}template <typename T,typename VST>void travPost_I(BinNodePosi(T) x,VST &visit){ stack<BinNodePosi<T> S; if(x) S.push(x); //如果根节点不为空,则push while(!S.empty()) { if(S.top()!=x->parent) //如果S中顶不是x的父节点 gotoHLVFL(S); //则进行查找 x=S.pop(); //否则pop() visit(x->data); }}
层次遍历:自高向低(按深度次序),自左向右遍历。我们发现从上往下满足先进先出的原理,所以采用队列queue来实现,从根节点出发,遇到左节点
template <typename T,typename VST>void BinNode<T>::travLevel(VST &visit){ Queue<BinNodePosi(T)> Q; Q.enqueue(this); while(!Q.empty()) { BinNodePosi(T) x=Q.dequeue(); //dequeue visit(x->data); if(HasLChild(*x)) Q.enqueue(x-lChild); //enqueue左孩子 if(HasRChild(*x)) Q.enqueue(x-rChild);//enqueue右孩子 }}
(d4)二叉树的重构:
(1)中序遍历+先序或者后序中的一种就可以进行重构
比较之后可以得出r的值,继而进一步比较。
(2)先序+后序 ——真二叉树(度数要么是0要么是2)
0 0
- 二叉树的遍历(层遍历和深度遍历)
- 二叉树的前序中序后序遍历,非递归遍历 层次遍历
- 二叉树的先中后序遍历,递归遍历,非递归遍历
- 二叉树遍历-----前序后序迭代遍历的新思路
- 二叉树的遍历-按层次遍历
- 二叉树的遍历(递归遍历)
- 二叉树的遍历-层次遍历
- 树的遍历
- 六、 树的遍历
- 二叉树的遍历
- haffman树的遍历
- 二叉树的遍历
- 树的各种遍历
- 树的遍历
- 二叉树的遍历
- C++树的遍历
- Java树的遍历
- 树的简单遍历
- Android之NDK开发
- 程序员保值的4个秘密
- AD(Active Directory)域信息同步,组织单位、用户等信息查询
- LeetCode_26---Remove Duplicates from Sorted Array
- 版本控制(八)--git分支&管理
- 树的遍历
- Git学习笔记(一)
- Python 学习之二:Python超短教程
- ios 打包ipa步骤
- js--window关闭事件
- 查看文件系统大小du df区别
- 应用程序开发选择工具应注重运行效率还是易用性
- Kickstart+NFS+DHCP+TFTP+PXElinux实现CentOS的网络自动安装
- 黑马程序员 java多线程