遍历二叉树

二叉树的遍历(traversing binary tree)是指从根结点出发,按照某种次序依次访问二叉树中所有的结点,使得每个结点被访问依次且仅被访问一次。
四种遍历方式分别为:先序遍历、中序遍历、后序遍历、层序遍历。

二叉树的四种遍历方式
例二叉树

直接用上面的二叉树上代码了,关于先序遍历、中序遍历、后序遍历的递归算法比较简单,不做注释,关于所有非递归算法的思想都在代码里写了注释。

先序遍历:ABDHEICFJKG
中序遍历:DHBEIAJFKCG
后序遍历:HDIEBJKFGCA
层序遍历:ABCDEFGHIJK

#include <stack>
#include <queue>
#include <cstdio>
using namespace std;

struct TreeNode {
    char val;
    TreeNode* leftChild;
    TreeNode* rightChild;
    TreeNode(char val) : val(val), leftChild(NULL), rightChild(NULL) {}
};

void PreorderTraversal(TreeNode* treeNode)
{
    if (NULL == treeNode)
    {
        return;
    }
    printf("%c", treeNode->val);
    PreorderTraversal(treeNode->leftChild);
    PreorderTraversal(treeNode->rightChild);
}
void InorderTraversal(TreeNode* treeNode)
{
    if (NULL == treeNode)
    {
        return;
    }
    InorderTraversal(treeNode->leftChild);
    printf("%c", treeNode->val);
    InorderTraversal(treeNode->rightChild);
}
void PostorderTraversal(TreeNode* treeNode)
{
    if (NULL == treeNode)
    {
        return;
    }
    PostorderTraversal(treeNode->leftChild);
    PostorderTraversal(treeNode->rightChild);
    printf("%c", treeNode->val);
}
/*
 * 先序遍历比较容易理解,首先将根节点入栈。
 * 从栈中取出栈顶节点,打印该点值,接着先将右孩子入栈。
 * 再将左孩子入栈(因为栈的特点是先进后出,要先遍历左孩子就得后入栈)。
 * 不断重复该步骤直至栈为空。
 */
void PreorderTraversalUnRecur(TreeNode* treeNode)
{
    if (NULL == treeNode)
    {
        return;
    }
    stack<TreeNode*> treeNodeStack;
    treeNodeStack.push(treeNode);
    while (!treeNodeStack.empty())
    {
        treeNode = treeNodeStack.top();
        treeNodeStack.pop();
        printf("%c", treeNode->val);
        if (treeNode->rightChild)
        {
            treeNodeStack.push(treeNode->rightChild);
        }
        if (treeNode->leftChild)
        {
            treeNodeStack.push(treeNode->leftChild);
        }
    }
}
/*
 * 中序遍历
 * 步骤1:比先把当前节点入栈,然后不停让treeNode=treeNode->leftChild,重复此步骤。
 *        即把treeNode下的所有左孩子节点入栈,直到treeNode为空。
 * 步骤2:从栈中弹出栈顶给treeNode,打印该节点,然后令treeNode=treeNode->rightChild,回到步骤1。
 * 步骤3:当栈为空时且treeNode为空时,过程结束。
 */
void InorderTraversalUnRecur(TreeNode* treeNode)
{
    if (NULL == treeNode)
    {
        return;
    }
    stack<TreeNode*> treeNodeStack;
    while (!treeNodeStack.empty() || NULL != treeNode)
    {
        while (NULL != treeNode)
        {
            treeNodeStack.push(treeNode);
            treeNode = treeNode->leftChild;
        }
        treeNode = treeNodeStack.top();
        treeNodeStack.pop();
        printf("%c", treeNode->val);
        treeNode = treeNode->rightChild;
    }
}
/*
 * 后序遍历(方法1)
 * 申请两个栈treeNodeStackl、treeNodeStack2,先将头节点入栈treeNodeStackl。
 * 从treeNodeStackl中弹出栈顶节点记为treeNode,然后依次将cur的左孩子和右孩子压入treeNodeStackl。
 * 在这过程中每一个从treeNodeStackl中弹出的节点均压入treeNodeStack2。
 * 当treeNodeStackl为空后,从treeNodeStack2中依次弹出的节点便是后序遍历的次序。
 * 主要就是利用两个栈来进行"倒腾",压入treeNodeStack2的顺序为中、右、左,弹出的顺序就变成了左、右、中。
 */
void PostorderTraversalUnRecur(TreeNode* treeNode)
{
    if (NULL == treeNode)
    {
        return;
    }
    stack<TreeNode*> treeNodeStackl, treeNodeStack2;
    treeNodeStackl.push(treeNode);
    while (!treeNodeStackl.empty())
    {
        treeNode = treeNodeStackl.top();
        treeNodeStackl.pop();
        treeNodeStack2.push(treeNode);
        if (treeNode->leftChild)
        {
            treeNodeStackl.push(treeNode->leftChild);
        }
        if (treeNode->rightChild)
        {
            treeNodeStackl.push(treeNode->rightChild);
        }
    }
    while (!treeNodeStack2.empty())
    {
        printf("%c", treeNodeStack2.top()->val);
        treeNodeStack2.pop();
    }
}
/*
 * 后序遍历(方法2)
 * 申请一个栈,将头节点压入栈。
 * 当遍历到一个节点时,如何判断这次遍历是打印该点,还是先处理它的孩子?有以下几种情况:
 * 1、该节点的左右孩子皆为空,即该节点为叶子节点,那么这次遍历就是打印该点。
 * 2、如果上一次打印的节点为该节点的右孩子,说明该节点的子树处理完毕,这次遍历就是打印该点。
 * 3、如果上一次打印的节点为该节点的左孩子,且该节点的右孩子为空,说明该节点的子树处理完毕,这次遍历就是打印该点。
 * 4、否则说明子树没有被访问过,按照右孩子、左孩子的顺序入栈。
*/
void PostorderTraversalUnRecur2(TreeNode* treeNode)
{
    if (NULL == treeNode)
    {
        return;
    }
    stack<TreeNode*> treeNodeStack;
    treeNodeStack.push(treeNode);
    TreeNode* last = NULL;
    TreeNode* top = NULL;
    while (!treeNodeStack.empty())
    {
        top = treeNodeStack.top();
        if ((top->leftChild == NULL && top->rightChild == NULL) ||
            (top->rightChild == NULL && last == top->leftChild) ||
            last == top->rightChild)
        {
            printf("%c", top->val);
            last = top;
            treeNodeStack.pop();
        }
        else
        {
            if (top->rightChild)
            {
                treeNodeStack.push(top->rightChild);
            }
            if (top->leftChild)
            {
                treeNodeStack.push(top->leftChild);
            }
        }
    }
}
/*
 * 层序遍历
 * 首先将二叉树的根节点push到队列中,如果队列不为空,就输出队头的元素并出队列。
 * 判断节点如果有孩子,就将孩子push到队列中。
 * 循环以上操作直到队列为空。
 */
void LevelOrder(TreeNode* treeNode)
{
    if (NULL == treeNode)
    {
        return;
    }
    queue<TreeNode*> queue;
    queue.push(treeNode);
    while (!queue.empty())
    {
        treeNode = queue.front();
        queue.pop();
        printf("%c", treeNode->val);
        if (treeNode->leftChild)
        {
            queue.push(treeNode->leftChild);
        }
        if (treeNode->rightChild)
        {
            queue.push(treeNode->rightChild);
        }
    }
}
int main()
{
    TreeNode nodeA('A');
    TreeNode nodeB('B');
    TreeNode nodeC('C');
    TreeNode nodeD('D');
    TreeNode nodeE('E');
    TreeNode nodeF('F');
    TreeNode nodeG('G');
    TreeNode nodeH('H');
    TreeNode nodel('T');
    TreeNode nodeJ('J');
    TreeNode nodeK('K');
    nodeA.leftChild = &nodeB;
    nodeA.rightChild = &nodeC;
    nodeB.leftChild = &nodeD;
    nodeB.rightChild = &nodeE;
    nodeD.rightChild = &nodeH;
    nodeE.rightChild = &nodel;
    nodeC.leftChild = &nodeF;
    nodeC.rightChild = &nodeG;
    nodeF.leftChild = &nodeJ;
    nodeF.rightChild = &nodeK;
    TreeNode* root = &nodeA;
    printf("      前序遍历:");      //ABDHEICFJKG
    PreorderTraversal(root);
    printf("\n");
    printf("前序遍历非递归:");     //ABDHEICFJKG
    PreorderTraversalUnRecur(root);
    printf("\n");
    printf("      中序遍历:");      //DHBEIAJFKCG
    InorderTraversal(root);
    printf("\n");
    printf("中序遍历非递归:");     //DHBEIAJFKCG
    InorderTraversalUnRecur(root);
    printf("\n");
    printf("      后序遍历:");      //HDIEBJKFGCA
    PostorderTraversal(root);
    printf("\n");
    printf("后序遍历非递归:");     //HDIEBJKFGCA
    PostorderTraversalUnRecur(root);
    printf("\n");
    printf("后序遍历非递归:");     //HDIEBJKFGCA
    PostorderTraversalUnRecur2(root);
    printf("\n");
    printf("      层序遍历:");      //ABCDEFGHIJK
    LevelOrder(root);
}

参考文章二叉树的四种遍历方式二叉树各种遍历算法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值