颜色遍历法非递归遍历二叉树

本文介绍了二叉树遍历中的颜色标记法,一种非递归通用解决方案,适用于前序、中序、后序和层次遍历。通过颜色区分节点状态,使代码简洁且易于理解,对于面试和LeetCode题目大有帮助。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二叉树的遍历主要有三种方法:前序遍历、中序遍历和后序遍历。这三种方法的非递归实现形式各有特点,较为复杂。然而,有一种通用的遍历方法——颜色标记法,可以应用于前序、中序、后序以及层次遍历。

之前笔试题遇到非递归遍历二叉树,平时都是递归写的,猝不及防的翻车了,在leetcode看见了这个方法,很神奇,基本都是100%击败,而且一套通用前序、中序、后序,学会了以后麻麻再也不用担心面试遇到写非递归遍历二叉树了,

学之前:各种奇怪的姿势利用栈模拟来遍历二叉树;
学之后:自信.jpg, 王之藐视.jpg,一套通杀!

一、方法解释

颜色标记法使用颜色来标识节点的状态。新访问的节点被标记为白色,已访问过的节点则为灰色。在遍历过程中,每当我们遇到一个白色节点,我们就将其标记为灰色,并将它和它的左右子节点依次压入栈中。如果遇到的节点是灰色的,则直接输出该节点的值。这种方法的优点在于其适用于各种类型的二叉树遍历,使得代码更加简洁并易于理解。

二、代码实现

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};


// 中序遍历
vector<int> inorderTraversal(TreeNode* root) {
    int white = 0, gray = 1;
    vector<int> res;
    vector<pair<int, TreeNode*>> stk;
    stk.push_back({white, root});
    while(!stk.empty()){
        auto [color, node] = stk.back();
        stk.pop_back();
        if(node == nullptr) continue;
        if(color == white){
            stk.push_back({white, node->right});
            stk.push_back({gray, node});
            stk.push_back({white, node->left});
        } else {
            res.push_back(node->val);
        }
    }
    return res;
}


// 前序遍历
vector<int> preorderTraversal(TreeNode* root) {
    int white = 0, gray = 1;
    vector<int> res;
    vector<pair<int, TreeNode*>> stk;
    stk.push_back({white, root});
    while(!stk.empty()){
        auto [color, node] = stk.back();
        stk.pop_back();
        if(node == nullptr) continue;
        if(color == white){  
            stk.push_back({white, node->right});
            stk.push_back({white, node->left});
            stk.push_back({gray, node});
        } else {
            res.push_back(node->val);
        }
    }
    return res;
}


// 后序遍历
vector<int> postorderTraversal(TreeNode* root) {
    int white = 0, gray = 1;
    vector<int> res;
    vector<pair<int, TreeNode*>> stk;
    stk.push_back({white, root});

    while(!stk.empty()){
        auto [color, node] = stk.back();
        stk.pop_back();
        if(node == nullptr) continue;
        if(color == white){
            stk.push_back({gray, node});
            stk.push_back({white, node->right});
            stk.push_back({white, node->left});
        } else {
            res.push_back(node->val);
        }
    }
    return res;
}

三、知识点练习

交封面图不杀,开始摇摆,耶~

在这里插入图片描述

### 非递归中序遍历的两种实现方法 #### 方法一:使用栈结构模拟递归过程 这种方法通过显式的栈数据结构来替代隐式的函数调用栈,从而实现了迭代版本的中序遍历。对于每一个节点,先尽可能地访问其左子树直到最左边的叶子结点,在此过程中依次将沿途遇到的所有节点压入栈内;一旦到达尽头,则弹出栈顶元素进行处理(即打印或保存),再转向右子树继续上述流程。 ```java public void inOrderTraversalWithStack(TreeNode root) { Stack<TreeNode> stack = new Stack<>(); TreeNode current = root; while (current != null || !stack.isEmpty()) { // Reach the left most Node of the current Node while (current != null) { stack.push(current); current = current.left; } // Current must be null at this point current = stack.pop(); System.out.print(current.val + " "); // Process node // We have visited the node and its left subtree. Now, it's right subtree's turn current = current.right; } } ``` #### 方法二:Morris 中序遍历法 不同于传统借助额外空间的做法,Morris 遍历利用了线索化二叉树的思想,能够在 O(1) 的辅助空间复杂度下完成中序遍历。具体来说就是调整某些指针指向使得能够回溯到父节点,这样就可以在不需要堆栈的情况下实现非递归遍历。需要注意的是,在实际编码时要小心恢复原始树形结构以免破坏输入的数据结构[^1]。 ```java public void morrisInorder(TreeNode root) { TreeNode current = root; while (current != null) { if (current.left == null) { System.out.print(current.val + " "); current = current.right; } else { // Find predecessor of current node which is largest value less than current val. TreeNode pre = current.left; while (pre.right != null && pre.right != current) { pre = pre.right; } if (pre.right == null) { // Make temporary link back to current so we can find our way up again later on. pre.right = current; current = current.left; } else { // Remove temporary link before visiting this node as part of output sequence, // because otherwise would create cycle within tree structure. pre.right = null; System.out.print(current.val + " "); current = current.right; } } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值