二叉树的前序/中序/后序遍历方法的递归与循环的实现

对于二叉树的三种遍历方法, 递归方法实现起来简单,明白。但是效率不好,并且不安全,可能会栈溢出。循环的实现,肯定是基于栈的数据结构来实现,要复杂一些。代码如下:

前序遍历的实现:

// 前序遍历 ----基于递归
void PreorderTraversal(BinaryTreeNode* pRoot_)
{
    // 为空时,直接返回了
    if (!pRoot_)
        return;

    std::cout << pRoot_->m_nValue << " ";
    PreorderTraversal(pRoot_->m_pLeft);
    PreorderTraversal(pRoot_->m_pRight);
}

// 前序遍历 ----基于循环
void PreorderTraversal_ByCycle(BinaryTreeNode* pRoot_)
{
    // 为空时,直接返回
    if (!pRoot_)
        return;

    // 需要使用到栈数据结构, 先把右子树放到栈中,再把左子树放到栈中
    stack<BinaryTreeNode*> _StackNodes;
    _StackNodes.push(pRoot_);
    while (!_StackNodes.empty())
    {
        BinaryTreeNode* _pCurrentNode = _StackNodes.top();
        _StackNodes.pop();
        std::cout << _pCurrentNode->m_nValue << " ";

        // 把非空的左右子节点放到栈中, 注意:要先放右节点,再放左节点
        BinaryTreeNode* _pRight = _pCurrentNode->m_pRight;
        BinaryTreeNode* _pLeft = _pCurrentNode->m_pLeft;
        if (_pRight)
            _StackNodes.push(_pRight);
        if (_pLeft)
            _StackNodes.push(_pLeft);

    }
}

中序遍历的实现:

// 中序遍历 ---- 基于递归
void InorderTraversal(BinaryTreeNode* pRoot_)
{
    // 为空时,直接返回
    if (!pRoot_)
        return;

    InorderTraversal(pRoot_->m_pLeft);
    std::cout << pRoot_->m_nValue << " ";
    InorderTraversal(pRoot_->m_pRight);
}

// 中序遍历 ---- 基于循环
void InorderTraversal_ByCycle(BinaryTreeNode* pRoot_)
{
    // 为空时,直接返回
    if (!pRoot_)
        return;

    // 初始化一个栈数据结构
    std::stack<BinaryTreeNode*> _StackNodes;

    // 先一股脑地把左子节点放到的栈中, 因为这时栈顶的叶结点就是我们遍历的起点
    BinaryTreeNode* _pCurrentNode = pRoot_;
    while (_pCurrentNode)
    {
        _StackNodes.push(_pCurrentNode);
        _pCurrentNode = _pCurrentNode->m_pLeft;
    }

    while (!_StackNodes.empty())
    {
        // 遍历栈顶的节点
        BinaryTreeNode* _pCurrentNode = _StackNodes.top();
        _StackNodes.pop();
        std::cout << _pCurrentNode->m_nValue << " ";

        // 即然遍历到了当前的节点,说明了它的左子树已经遍历完了,不需要管了。 我们现在
        // 需要关注的是:当前节点的右子树是否为空了, 如果不为空,则需要去处理一下了。
        _pCurrentNode = _pCurrentNode->m_pRight;
        while (_pCurrentNode)
        {
            _StackNodes.push(_pCurrentNode);
            _pCurrentNode = _pCurrentNode->m_pLeft;
        }
    }
}

后序遍历的实现:

// 后序遍历 ---- 基于递归
void PostorderTraversal(BinaryTreeNode* pRoot_)
{
    // 为空时,直接返回
    if (!pRoot_)
        return;

    PostorderTraversal(pRoot_->m_pLeft);
    PostorderTraversal(pRoot_->m_pRight);
    std::cout << pRoot_->m_nValue << " ";
}

// 后序遍历 ---- 基于循环
void PostorderTraversal_ByCycle(BinaryTreeNode* pRoot_)
{
 // 为空时,直接返回
    if (!pRoot_)
        return;

    // 使用一个栈的数据结构
    std::stack<BinaryTreeNode*> _StackNodes;

    // 把我们查找第一个应该遍历的node的路径上经过的所有node按顺序一股脑地压入栈中
    BinaryTreeNode* _pCurrentNode = pRoot_;
    while (_pCurrentNode)
    {
        _StackNodes.push(_pCurrentNode);
        // 优先选择不为空的左节点,如果左节点为空,再考虑右节点(右节点为空也没有关系)
        if (_pCurrentNode->m_pLeft)
            _pCurrentNode = _pCurrentNode->m_pLeft;
        else
            _pCurrentNode = _pCurrentNode->m_pRight;
    }

    while (!_StackNodes.empty())
    {
        // 遍历栈顶的节点
        BinaryTreeNode* _pCurrentNode = _StackNodes.top();
        _StackNodes.pop();
        std::cout << _pCurrentNode->m_nValue << " ";

        // 既然遍历到了当前节点,说明它的左子树与右子树都遍历完了,不需要管了。我们现在
        // 需要关注的是: 如果当前节点为父节点的左节点,则需要判断父节点的右节点是否为空.
        // 如果不为空,则需要去处理父节点的右节点了。
        //
        // 另外,如果当前节点不右父节点的右节点,也不需要管,因为接下来会去遍历父节点。
        if (!_StackNodes.empty() && _pCurrentNode == _StackNodes.top()->m_pLeft)
        {
            _pCurrentNode = _StackNodes.top()->m_pRight;
            while (_pCurrentNode)
            {
                _StackNodes.push(_pCurrentNode);
                // 优先选择左节点,当左节点为空时,再选择右节点(右节点为空,也没事)
                if (_pCurrentNode->m_pLeft)
                    _pCurrentNode = _pCurrentNode->m_pLeft;
                else
                    _pCurrentNode = _pCurrentNode->m_pRight;
            }
        }
    }
}

最后,补充一个宽度优先遍历的实现,即一层层地遍历:

分层遍历:

// 宽度优先遍历,就是一层层地遍历。 这肯定是基于单端队列来实现
void BreadthFirstTraversal(BinaryTreeNode* pRoot_)
{
    if (!pRoot_)
        return;

    std::queue<BinaryTreeNode*> _QueueNodes;
    _QueueNodes.push(pRoot_);
    while (!_QueueNodes.empty())
    {
        BinaryTreeNode* _pCurrentNode = _QueueNodes.front();
        _QueueNodes.pop();
        std::cout << _pCurrentNode->m_nValue << " ";

        // 把当前节点的左右非空子节点放入到队列中
        BinaryTreeNode* _pLeft = _pCurrentNode->m_pLeft;
        BinaryTreeNode* _pRight = _pCurrentNode->m_pRight;
        if (_pLeft)
            _QueueNodes.push(_pLeft);
        if (_pRight)
            _QueueNodes.push(_pRight);
    }
}

原文地址:https://www.cnblogs.com/yinheyi/p/10668108.html

时间: 2024-10-29 10:39:45

二叉树的前序/中序/后序遍历方法的递归与循环的实现的相关文章

分别求二叉树前、中、后序的第k个节点

一.求二叉树的前序遍历中的第k个节点 //求先序遍历中的第k个节点的值 int n=1; elemType preNode(BTNode *root,int k){ if(root==NULL) return ' '; if(n==k) return root->data; n++; elemType ch = preNode(root->lchild,k); if(ch!=' ') return ch; ch = preNode(root->rchild,k); return ch;

算法实验-二叉树的创建和前序-中序-后序-层次 遍历

对于二叉树的创建我是利用先序遍历的序列进行创建 能够对于树节点的内容我定义为char型变量 '0'为空,即此处的节点不存在 头文件 Tree.h //链式二叉树的头文件 #pragma once #include<iostream> #include<queue> using namespace std; class BinaryTreeNode { public: char data; BinaryTreeNode *leftChild,*rightChild; BinaryTr

二叉树的前序中序后序遍历相互求法

二叉树的前中后序遍历,他们的递归非递归.还有广度遍历,参见二叉树的前中后序遍历迭代&广度遍历和二叉树的前中后序遍历简单的递归 现在记录已知二叉树的前序中序后序遍历的两个,求另外一个.一般,这两个中一定有中序遍历. 1.已知前序和中序,求后序遍历: 前序:ABDECFG  中序:DBEAFCG 思路简单:前序的第一个节点就是根节点, 中序中找到根节点的位置,根节点之前是其左子树,之后是右子树   按此顺序,依次在左子树部分遍历,右子树部分遍历 C++ 代码: TreeNode *BinaryTre

二叉树前序、中序和后序的遍历方法(递归、用栈和使用线索化)

在2^k*2^k个方格组成的棋盘中,有一个方格被占用,用下图的4种L型骨牌覆盖所有棋盘上的其余所有方格,不能重叠. 代码如下: def chess(tr,tc,pr,pc,size): global mark global table mark+=1 count=mark if size==1: return half=size//2 if pr<tr+half and pc<tc+half: chess(tr,tc,pr,pc,half) else: table[tr+half-1][tc+

已知二叉树前、中序遍历,求后序 / 已知二叉树中、后序遍历,求前序

void solve(int start,int end,int root) { // 前序和中序 -> 后序 // 每次调用solve()函数,传入pre-order的start,end,root if (start > end) // 递归边界 return; int i = start; while (i < end && in.at(i) != pre.at(root)) // 找到左右子树的分割点 i++; solve(start, i - 1, root +

经典白话算法之二叉树中序前序序列(或后序)求解树

这种题一般有二种形式,共同点是都已知中序序列.如果没有中序序列,是无法唯一确定一棵树的. <1>已知二叉树的前序序列和中序序列,求解树. 1.确定树的根节点.树根是当前树中所有元素在前序遍历中最先出现的元素. 2.求解树的子树.找出根节点在中序遍历中的位置,根左边的所有元素就是左子树,根右边的所有元素就是右子树.若根节点左边或右边为空,则该方向子树为空:若根节点 边和右边都为空,则根节点已经为叶子节点. 3.递归求解树.将左子树和右子树分别看成一棵二叉树,重复1.2.3步,直到所有的节点完成定

【数据结构】二叉树(前、中、后)序遍历的递归与非递归算法

对于二叉树,有前序.中序以及后序三种遍历方法.因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易理解而且代码很简洁.而对 于树的遍历若采用非递归的方法,就要采用栈去模拟实现.在三种遍历中,前序和中序遍历的非递归算法都很容易实现,非递归后序遍历实现起来相对来说要难一 点. 二叉树前序:访问根节点->左子树->右子树 (1)递归写法: 依次访问根节点.左子树.右子树,注意递归出口的结束. void _PrevOrder(Node* root)     {         i

日常学习随笔-用链表的形式实现普通二叉树的新增、查找、遍历(前、中、后序)等基础功能(侧重源码+说明)

一.二叉树 1.二叉树的概念 二叉树是每个节点最多有两个子树的树结构.通常子树被称作"左子树"(left subtree)和"右子树"(right subtree),其次序不能任意颠倒. 2.性质 (1)若二叉树的层次从0开始,则在二叉树的第i层至多有2^i个结点(i>=0): (2)高度为k的二叉树最多有2^(k+1) - 1个结点(k>=-1). (空树的高度为-1): (3)对任何一棵二叉树,如果其叶子结点(度为0)数为m, 度为2的结点数为n,

算法进阶面试题03——构造数组的MaxTree、最大子矩阵的大小、2017京东环形烽火台问题、介绍Morris遍历并实现前序/中序/后序

接着第二课的内容和带点第三课的内容. (回顾)准备一个栈,从大到小排列,具体参考上一课.... 构造数组的MaxTree [题目] 定义二叉树如下: public class Node{ public int value; public Node left; public Node right; public Node(int data){ this.value=data; } } 一个数组的MaxTree定义如下: ◆ 数组必须没有重复元素 ◆ MaxTree是一颗二叉树,数组的每一个值对应一