【数据结构】 -- 二叉树的遍历

样例:

输入树的结构如下:

​  1
​  2    3
​ 4     5
​   6

前序遍历结果:

1, 2 ,4, 6, 3, 5

中序遍历结果:

4, 6, 2, 1, 3, 5

后序遍历结果:

6, 4, 2, 5, 3, 1

层次遍历结果:

1, 2, 3, 4, 5, 6

1. 前序遍历

按照根节点->左孩子->右孩子的访问顺序

  1. 递归版本

    // 前序遍历递归版本
    void PreOrder(TreeNode* pRoot)
    {
        if (pRoot != NULL)
        {
            cout << pRoot->val << " ";
            PreOrder(pRoot->left);
            PreOrder(pRoot->right);
        }
    }
  2. 非递归版本

    // 前序遍历非递归版本
    // 栈后进先出刚好符合前序遍历(根,左,右)特点,先push右孩子,在push左孩子
    // 则打印过程先打印栈顶元素,然后再依次压入栈顶的右孩子,左孩子,依次循环
    void PreOrderStack(TreeNode* pRoot)
    {
        if (pRoot != NULL)
        {
            stack<TreeNode*> temp;
            temp.push(pRoot);
            while (!temp.empty())
            {
                TreeNode* node = temp.top();
                cout << node->val << " ";   // 打印栈顶元素的值
                temp.pop();
                if (node->right != NULL)  // 有右孩子,先压入右孩子
                    temp.push(node->right);
                if (node->left != NULL)
                    temp.push(node->left);
            }
        }
    }
2. 中序遍历

按照左孩子->根节点->右孩子的访问顺序

  1. 递归版本

    // 中序遍历递归版本
    void InOrder(TreeNode* pRoot)
    {
        if (pRoot != NULL)
        {
            InOrder(pRoot->left);
            cout << pRoot->val << " ";
            InOrder(pRoot->right);
        }
    }
  2. 非递归版本

    // 中序遍历非递归版本
    void InOrderStack(TreeNode* pRoot)
    {
        if (pRoot != NULL)
        {
            stack<TreeNode*> temp;
            TreeNode* node = pRoot;
    
            while (node!=NULL || !temp.empty()) //node!=NULL 保证第一次能进入循环
            {
                if (node != NULL)     // node 有值时,将该节点压入栈中
                {
                    temp.push(node);
                    node = node->left;      // node指向左孩子
                }
                else                         // node 没有值时,已经到达叶子结点的孩子节点(NULL)或者没有左孩子的情况
                {
                    node = temp.top();            // 将node指向栈顶即叶子结点
                    cout << node->val << " ";
                    temp.pop();          
                    node = node->right;      // node指向右孩子
                }
            }
        }
    }
3. 后序遍历

按照左孩子->右孩子->根节点的访问顺序

  1. 递归版本

    // 后序遍历递归版本
    void LastOrder(TreeNode* pRoot)
    {
        if (pRoot != NULL)
        {
            LastOrder(pRoot->left);
            LastOrder(pRoot->right);
            cout << pRoot->val << " ";
        }
    }
  2. 非递归版本1

    // 后序遍历非递归版本
    void LastOrderStack1(TreeNode* pRoot)
    {
        if (pRoot == NULL)
            return;
        stack<TreeNode*> stack1, stack2;  // 设计两个栈,栈1按根左右入栈,栈2每次迭代压入栈1栈顶元素
        stack1.push(pRoot);               // 由于栈后进先出的特点实际上栈2保存顺序为根->右子树->左子树
        while (!stack1.empty())
        {
            TreeNode* node = stack1.top();
            stack2.push(node);
            stack1.pop();
            if (node->left != NULL)
                stack1.push(node->left);
            if (node->right != NULL)
                stack1.push(node->right);
        }
        while (!stack2.empty())    // 栈2按出栈顺序打印则实现后序遍历
        {
            int val = stack2.top()->val;
            cout << val << " ";
            stack2.pop();
        }
    }
  3. 非递归版本2

    void LastOrderStack2(TreeNode* pRoot)
    {
        if (pRoot == NULL)
            return;
        stack<TreeNode*> temp;
        TreeNode* node = pRoot;   // node和栈temp共同控制迭代顺序
        TreeNode* Last = NULL;
        while (node!=NULL || !temp.empty())
        {
            if (node != NULL)       // node有值时压入栈(优先压入左孩子)
            {
                temp.push(node);
                node = node->left;
            }
            else 
            {
                TreeNode* top = temp.top();     // node为NULL时,以栈顶元素为判断条件
                if (top->right != NULL&&Last != top->right)   // 当栈顶元素有右孩子且不为上一次pop出的元素
                {                                                 
                    node = top->right;                       // node指向栈顶元素的右孩子
                }
                else
                {
                    cout << top->val << " ";
                    temp.pop();
                    Last = top;                     // Last 记录上次pop元素,防止重复遍历
                }
            }
        }
    }
4. 层次遍历

访问二叉树时,逐层访问,每层从左节点一直访问到右节点

    // 广度优先遍历(层次遍历)
    void LevelTraversal(TreeNode* pRoot)
    {
        if (pRoot == NULL)
            return;

        queue<TreeNode*> temp;  // 采用队列控制迭代
        temp.push(pRoot);
        while (!temp.empty())
        {
            TreeNode* node = temp.front();   // 按根左右压入队列,由于队列先进先出的特点
            cout << node->val << " ";
            temp.pop();                      // 弹出顺序即为层次遍历顺序
            if (node->left != NULL)
                temp.push(node->left);
            if (node->right != NULL)
                temp.push(node->right);
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值