树的遍历

来源:互联网 发布: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