二叉树的四种遍历的递归和非递归的实现

二叉树的三种遍历为:前序遍历,中序遍历和后序遍历。

遍历的实现可分为递归和非递归。递归法与二叉树的定义相似,非递归法采用栈去模拟实现。

一、前序遍历的次序为:根结点——左结点——右结点。

递归法实现:

//前序遍历的递归实现
void preOrder1(BinaryTreeNode* pRoot)
{
    if(pRoot==NULL)
       return;

    cout<<pRoot->value;
    if(pRoot->left!=NULL)
       preOrder1(pRoot->left);
    if(pRoot->right!=NULL)
       preOrder1(pRoot->right);
}
非递归的实现:

前序遍历的访问顺序为:根,左和右。对于任一结点,其可看做根结点,因此可直接访问。访问完后,若其左孩子不为空,则按照相同规则访问它的左子树;访问完左子树,再访问它的右子树。处理过程如下:

对于任一结点P:

step 1:访问结点p,并将结点p入栈。

step 2:判断结点p的左孩子是否为空。若为空,则取栈顶结点并出栈,将栈顶元素的右孩子设为当前的结点p,循环至step 1。

            若不为空,则将p的左孩子设为当前结点p。

step 3:直到p为NULL,并且栈为空,则遍历结束。

//前序遍历的非递归遍历
void preOrder2(BinaryTreeNode* pRoot)
{
    stack<BinaryTreeNode*> s;
    BinaryTreeNode *p=pRoot;

    if(pRoot==NULL)
        return;
    while(p!=NULL||!s.empty())
    {
       while(p!=NULL)
       {
           cout<<p->value<<" ";
           s.push(p);
           p=p->left;
       }
       if(!s.empty())
       {
           p=s.top();
           s.pop();
           p=p->right;
       }
    }
}
二、中序遍历的次序为:左结点——根结点——右结点

递归法:

//中序遍历的递归法
void inOrder1(BinaryTreeNode* pRoot)
{
    if(pRoot==NULL)
        return;
    
    if(pRoot->left!=NULL)
        inOrder1(pRoot->left);
    cout<<pRoot->value;
    if(pRoot->right!=NULL)
        inOrder1(pRoot->right);
}
非递归法:

根据中序遍历的顺序,对于任一结点,先访问其左孩子。而左孩子又可以看做一个根结点,然后继续访问左孩子,直到遇到的左孩子结点为空,则停止访问。然后访问右孩子。

处理过程如下:

对于任一结点p:

step 1:若其左孩子不为空,则将p入栈,并将p的左孩子置为当前的p。然后对当前结点p再进行相同的处理。

step 2:若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将栈顶结点的右孩子置为当前的P结点。

step 3:直到p为NULL并且栈为空则遍历结束。

//中序遍历的非递归法
void inOrder(BinaryTreeNode* pRoot)
{
    stack<BinaryTreeNode*> s;
    BinaryTreeNode *p=pRoot;
    while(p!=NULL||!s.empty())
    {
        while(p!=NULL)
        {
            s.push(p);
            p=p->left;
        }
        if(!s.empty())
        {
            p=s.top();
            cout<<p->value;
            s.pop();
            p=p->right;
        }
    }
}
三、后序遍历

递归法:左结点——右结点——根结点。

//后序遍历的递归法
void postOrder1(BinaryTreeNode* pRoot)
{
    if(pRoot==NULL)
        return;
    postOrder1(pRoot->left);
    postOrder1(pRoot->right);
    cout<<pRoot->value<<" ";
}
非递归遍历:要保证根结点在左孩子和右孩子访问之后才能访问。因此对于任一结点p,先将其入栈。

若p不存在左孩子和右孩子,则可以直接访问它。或者p存在左孩子或者右孩子,但是左孩子和右孩子都已经被访问过了,则可以直接访问该结点。

若非上述两种情况,则将右孩子和左孩子依次入栈。这样可以保证每次取栈顶元素时,左孩子在右孩子前面被访问,根结点在左孩子和右孩子访问之后被访问。

//后序遍历的非递归法
void postOrder(BinaryTreeNode* pRoot)
{
    stack<BinaryTreeNode*> s;
    BinaryTreeNode *cur;
    BinaryTreeNode *pre=NULL;
    s.push(pRoot);//根结点入栈
    while(!s.empty())
    {
        cur=s.top();
        if((cur->left==NULL&&cur->right==NULL)||(pre!=NULL&&(pre==cur->left||pre==cur->right)))
        {
            //左孩子和右孩子同时为空,或者当前结点的左孩子或右孩子已经遍历过了
            cout<<cur->value<<" ";
            s.pop();
            pre=cur;
        }
        else
        {
            if(cur->right!=NULL)
                s.push(cur->right);
            if(cur->left!=NULL)
                s.push(cur->left);
        }
    }
}

四、层次遍历(剑指Offer上有涉及)


题目:从上到下打印二叉树的每个节点,同层的节点按照从左向右打印。

解析:即分层遍历二叉树。利用广度优先遍历的思想,遍历树或者有向图,都可在队列中完成。

step1:把起始节点放入队列。

step2:每次从队头取出节点,遍历(输出)。接下来,把从该节点能到达的节点(子树或者其他)都依次放入队列。

重复step2,直到队列中的节点为空。

void PrintFromTopToBottom(BinaryTreeNode* pRoot)
{
    if(pRoot == NULL)
        return;

    std::deque<BinaryTreeNode *> dequeTreeNode;

    dequeTreeNode.push_back(pRoot);

    while(dequeTreeNode.size())
    {
        BinaryTreeNode *pNode = dequeTreeNode.front();
        dequeTreeNode.pop_front();

        printf("%d ", pNode->m_nValue);

        if(pNode->m_pLeft)
            dequeTreeNode.push_back(pNode->m_pLeft);

        if(pNode->m_pRight)
            dequeTreeNode.push_back(pNode->m_pRight);
    }
}





  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值