zoukankan      html  css  js  c++  java
  • 二叉树(4)非递归法遍历二叉树

          首先递归法是操作二叉树的首选方法。非递归法也分前序、中序、后序三种。后序比较特殊,我们在二叉树的节点中设置了成员变量flag,约定创建节点时候初始化为false。定义如下:


    typedef struct BinaryTreeNode  
    {  
        int data;  
        BinaryTreeNode * leftchild;  
        BinaryTreeNode * rightchild; 
        bool flag;//一定初始化为0
    }Node,*NodePoint;

        

    1.非递归前序遍历

    void NonRecursivePreOrder(NodePoint Root)
    {
        stack<NodePoint> s;    
        NodePoint p = Root;
        while(p)
        {
          cout<<p ->data<<"  ";  
          if(p->rightchild)  
    	 s.push(p->rightchild);//注意此处的顺序,先压入右孩子再压入左孩子
          if(p->leftchild)
             s.push(p->leftchild);
          if(s.empty()) 
             break;
          else 
            {p = s.top();s.pop();}
        }
    }


             前序=根左右。对于任一个节点,先输出节点值,然后再操作左子树,因此右子树先压入stack。紧接着的是弹出top顶端的指针进行操作,若上一步左子树为空,则弹出的指针指向右子树。如果上一级的左右孩子均为空,则弹出的为指向上2级的右子树的指针,以此完成递归操作。这里需要控制的压入stack的当前子树先后,大范围来说,操作完某一个节点的左子树,再操作其右子树。

              使用栈的非递归前序遍历的另外一种形式:

    void NonRecursivePreOrder(NodePoint Root)
    {
        stack<NodePoint> s;    
      
        while(Root||!s.empty())
        {  
    	if(Root){
               cout<<Root->data;
               s.push(Root);
               Root=Root->leftchild;         
            }
            else{
              Root=s.top();
              s.pop();
              Root=Root->rightchild;
            }
        }
    }


    
    

    2.非递归中序遍历

    void NonRecursiveInOrder(NodePoint Root)
    {
        stack<NodePoint> s;
        NodePoint p = Root;
        while(p||!s.empty())
        {
            while(p) 
               {s.push(p);           
                p = p->leftchild;} 
            p = s.top();
            s.pop();//弹出的根节点
            cout<<p ->data<<" ";
            p = p->rightchild; }
    }


                   中序=左根右。首先找到某个节点的最左边的节点,以此控制向后退和向右转。找到最左边的节点后,接着做的是判断其右子树是否空。倘若为空,则弹出指向上两级节点的指针。倘若不为空,则遍历以右孩子为根节点的子树的最左边的节点。节点一旦输出,马上弹出。

          另外一种非递归中序遍历:

    void NonRecursiveInOrder(NodePoint Root)
    {
        stack<NodePoint> s;    
        while(Root||!s.empty())
        {  
    	   if(Root){           
    	        s.push(Root);
                Root=Root->leftchild; }
    	    else{ 
    	        Root=s.top(); 
    	        s.pop(); 
                cout<<Root->data; 
    	        Root=Root->rightchild; } 
    	    }
    	}
    }

    3.非递归后序遍历

    void NonRecursivePostOrder(NodePoint Root)
    {
         stack<NodePoint>  s;
         NodePoint p=Root;
         while(p||!s.empty()){
    	while(p){
              s.push(p);
              p=p->leftchild;//遍历至最左根节点
    	}
            p=s.top();
            if(p->flag||!p->rightchild)//p尚且不能输出,或者右子树为NULL
              {cout<<p->data<<" ";
    	   s.pop();
    	   p=NULL;}//先赋值,仅仅在满足条件的时候,再将元素弹出stack,此处弹出的为子‘根’节点
           else
          	  {p->flag=true;
    	  p=p->rightchild;}//顺序不能换 
       }
    }


    
    
    
    
    
    

               后序=左右根。先输出左子树。倘若右子树为空,或者后退的时候已经显示遍历过了,那么输出当前节点数据并弹出stack即可;倘若不为空,则对以右子树为根节点的子树遍历左节点压栈。

    4.非递归层序遍历

           需要使用队列,满足先遍历的节点。且子节点也要先遍历。

    void NonRecursivelevelOrder(Tree Root){
    	queue<Node> q;
    	Tree temp;
    	q.push(Root);
    	while(!q.empty()){
    	  temp=q.front();
    	  q.pop();
    	  cout<<Root->data;
             if(Root->leftchild)
    	    q.push(Root->leftchild);
    	 if(Root->rightchild)
    	   q.push(Root->rightchild);
    	}
    }



         非递归算法的时间复杂度和空间复杂度都是O(n)。二叉树的遍历算法中,每个算法都访问了节点的每一个域,其每个域仅被访问一次,故时间复杂度为O(n),三种非递归遍历中,栈的最大空间为深度k倍的节点元素存储空间,最坏的情况,空间复杂度也为O(n)。层序遍历时,队列的最大长度不会超过二叉树中某一层最多的节点数,故最坏的情况空间复杂度也是O(n)。

        不论是那种遍历方式,仅仅考虑叶子节点,排序方式都是从左到右。





    部分参考修改自:二叉树常用算法总结



  • 相关阅读:
    [django]django models最佳实战
    [vue]模拟移动端三级路由: router-link位置体现router的灵活性
    [js]顶部导航和内容区布局
    [django]django查询最佳实战
    [vue]webpack使用样式
    [vue]webpack中使用组件
    [vue]组件的导入
    [django]django权限简单实验
    [django]前后端分离之JWT用户认证
    [django]drf知识点梳理-权限
  • 原文地址:https://www.cnblogs.com/engineerLF/p/5393135.html
Copyright © 2011-2022 走看看