树的遍历(二叉树、N叉树)

树的遍历

以Leetcode上面的题目为例演示二叉树、N叉树的递归遍历以及经典非递归遍历方式。

一. 二叉树的遍历

二叉树的定义

  • C++
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;

    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
  • Java
public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x){
        val = x;
    }
}

Leetcode 0144 二叉树的前序遍历

问题描述

分析

  • 前序遍历:根左右

代码

  • C++
// 递归
/**
 * 执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
 * 内存消耗:8.2 MB, 在所有 C++ 提交中击败了73.18%的用户
 */
class Solution {
public:
    vector<int> res;

    vector<int> preorderTraversal(TreeNode *root) {
        dfs(root);
        return res;
    }

    void dfs(TreeNode *root) {
        if (!root) return;
        res.push_back(root->val);
        dfs(root->left);
        dfs(root->right);
    }
};
// 非递归
/**
 * 执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
 * 内存消耗:8.2 MB, 在所有 C++ 提交中击败了65.63%的用户
 */
class Solution {
public:
    vector<int> preorderTraversal(TreeNode *root) {
        vector<int> res;
        stack<TreeNode *> stk;
        while (root || stk.size()) {
            while (root) {
                res.push_back(root->val);
                stk.push(root);
                root = root->left;
            }
            root = stk.top()->right;
            stk.pop();
        }
        return res;
    }
};
  • Java
/**
 * 递归算法
 * 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
 * 内存消耗:36.6 MB, 在所有 Java 提交中击败了82.16%的用户
 */
public class Solution {
    ArrayList<Integer> res = new ArrayList<>();

    public List<Integer> preorderTraversal(TreeNode root) {
        dfs(root);
        return res;
    }

    private void dfs(TreeNode root) {
        if (root == null) return;
        res.add(root.val);
        dfs(root.left);
        dfs(root.right);
    }
}
/**
 * 非递归算法
 * 执行用时:1 ms, 在所有 Java 提交中击败了45.75%的用户
 * 内存消耗:36.8 MB, 在所有 Java 提交中击败了30.16%的用户
 */
public class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {

        ArrayList<Integer> res = new ArrayList<>();
        Deque<TreeNode> stk = new ArrayDeque<>();
        while (root != null || !stk.isEmpty()) {
            while (root != null) {
                res.add(root.val);
                stk.push(root);
                root = root.left;
            }
            root = stk.pop().right;
        }
        return res;
    }
}

Leetcode 0094 二叉树的中序遍历

问题描述

分析

  • 中序遍历:左根右

代码

  • C++
// 递归
/**
 * 执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
 * 内存消耗:8.2 MB, 在所有 C++ 提交中击败了60.90%的用户
 */
class Solution {
public:
    vector<int> res;

    vector<int> inorderTraversal(TreeNode *root) {
        dfs(root);
        return res;
    }

    void dfs(TreeNode *root) {
        if (!root) return;
        dfs(root->left);
        res.push_back(root->val);
        dfs(root->right);
    }
};
// 非递归
/**
 * 执行用时:4 ms, 在所有 C++ 提交中击败了47.82%的用户
 * 内存消耗:8.1 MB, 在所有 C++ 提交中击败了94.94%的用户
 */
class Solution {
public:
    vector<int> inorderTraversal(TreeNode *root) {
        vector<int> res;
        stack<TreeNode *> stk;
        while (root || stk.size()) {
            while (root) {
                stk.push(root);
                root = root->left;
            }
            root = stk.top(), stk.pop();
            res.push_back(root->val);
            root = root->right;
        }
        return res;
    }
};
  • Java
/**
 * 递归算法
 * 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
 * 内存消耗:36.6 MB, 在所有 Java 提交中击败了70.81%的用户
 */
public class Solution {
    ArrayList<Integer> res = new ArrayList<>();

    public List<Integer> inorderTraversal(TreeNode root) {
        dfs(root);
        return res;
    }

    private void dfs(TreeNode node) {
        if (node == null) return;
        dfs(node.left);
        res.add(node.val);
        dfs(node.right);
    }
}
/**
 * 非递归算法
 * 执行用时:1 ms, 在所有 Java 提交中击败了41.71%的用户
 * 内存消耗:36.9 MB, 在所有 Java 提交中击败了12.74%的用户
 */
public class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {

        ArrayList<Integer> res = new ArrayList<>();
        Deque<TreeNode> stk = new ArrayDeque<>();
        while (root != null || !stk.isEmpty()) {
            while (root != null) {
                stk.push(root);
                root = root.left;
            }
            root = stk.pop();
            res.add(root.val);
            root = root.right;
        }
        return res;
    }
}

Leetcode 0145 二叉树的后序遍历

问题描述

分析

  • 后序遍历:左右根

代码

  • C++
// 递归
/**
 * 执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
 * 内存消耗:8.1 MB, 在所有 C++ 提交中击败了87.63%的用户
 */
class Solution {
public:
    vector<int> res;

    vector<int> postorderTraversal(TreeNode *root) {
        dfs(root);
        return res;
    }

    void dfs(TreeNode *root) {
        if (!root) return;
        dfs(root->left);
        dfs(root->right);
        res.push_back(root->val);
    }
};
// 非递归
/**
 * 执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
 * 内存消耗:8.1 MB, 在所有 C++ 提交中击败了94.56%的用户
 */
class Solution {
public:
    // 思路:后序遍历是:左右根,反过来就是:根右左; 按照根右左遍历后,结果再翻转一下即可
    vector<int> postorderTraversal(TreeNode *root) {
        vector<int> res;
        stack<TreeNode *> stk;
        while (root || stk.size()) {
            while (root) {
                res.push_back(root->val);
                stk.push(root);
                root = root->right;
            }
            root = stk.top()->left;
            stk.pop();
        }
        reverse(res.begin(), res.end());
        return res;
    }
};
  • Java
/**
 * 递归算法
 * 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
 * 内存消耗:37 MB, 在所有 Java 提交中击败了5.32%的用户
 */
public class Solution {
    ArrayList<Integer> res = new ArrayList<>();

    public List<Integer> postorderTraversal(TreeNode root) {
        dfs(root);
        return res;
    }

    private void dfs(TreeNode node) {
        if (node == null) return;
        dfs(node.left);
        dfs(node.right);
        res.add(node.val);
    }
}
/**
 * 非递归算法
 * 执行用时:1 ms, 在所有 Java 提交中击败了53.31%的用户
 * 内存消耗:36.7 MB, 在所有 Java 提交中击败了54.95%的用户
 */
public class Solution {
    // 思路:后序遍历是:左右根,反过来就是:根右左; 按照根右左遍历后,结果再翻转一下即可
    public List<Integer> postorderTraversal(TreeNode root) {

        ArrayList<Integer> res = new ArrayList<>();
        Deque<TreeNode> stk = new ArrayDeque<>();
        while (null != root || !stk.isEmpty()) {
            while (null != root) {
                res.add(root.val);
                stk.push(root);
                root = root.right;
            }
            root = stk.pop().left;
        }
        Collections.reverse(res);
        return res;
    }
}

Leetcode 0102 二叉树的层序遍历

问题描述

分析

  • 层序遍历:逐层地,从左到右访问所有节点

代码

  • C++
/**
 * 执行用时:4 ms, 在所有 C++ 提交中击败了89.06%的用户
 * 内存消耗:11.3 MB, 在所有 C++ 提交中击败了97.27%的用户
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode *root) {

        vector<vector<int>> res;
        queue<TreeNode *> q;
        if (root) q.push(root);
        while (q.size()) {
            vector<int> level;
            int len = q.size();

            while (len--) {
                auto t = q.front();
                q.pop();
                level.push_back(t->val);
                if (t->left) q.push(t->left);
                if (t->right) q.push(t->right);
            }
            res.push_back(level);
        }
        return res;
    }
};
  • Java
/**
 * 执行用时:1 ms, 在所有 Java 提交中击败了94.42%的用户
 * 内存消耗:38.8 MB, 在所有 Java 提交中击败了21.83%的用户
 */
public class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {

        List<List<Integer>> res = new ArrayList<>();
        Queue<TreeNode> q = new LinkedList<>();
        if (root != null) q.add(root);
        while (!q.isEmpty()) {
            List<Integer> level = new ArrayList<>();
            int len = q.size();
            for (int i = 0; i < len; i++) {
                TreeNode t = q.remove();
                level.add(t.val);
                if (t.left != null) q.add(t.left);
                if (t.right != null) q.add(t.right);
            }
            res.add(level);
        }
        return res;
    }
}

二. N叉树的遍历

N叉树的定义

  • C++
class Node {
public:
    int val;
    vector<Node *> children;
    Node() {}
    Node(int _val) { val = _val; }
    Node(int _val, vector<Node *> _children) {
        val = _val;
        children = _children;
    }
};
  • Java
public class Node {
    public int val;
    public List<Node> children;
    public Node() {}
    public Node(int _val) { val = _val; }
    public Node(int _val, List<Node> _children) {
        val = _val;
        children = _children;
    }
};

Leetcode 0589 N叉树的前序遍历

问题描述

分析

  • N叉树的前序遍历:根,从左到右遍历该根对应的孩子

代码

  • C++
// 递归
/**
 * 执行用时:16 ms, 在所有 C++ 提交中击败了96.71%的用户
 * 内存消耗:11.3 MB, 在所有 C++ 提交中击败了62.70%的用户
 */
class Solution {
public:
    vector<int> res;

    vector<int> preorder(Node *root) {
        dfs(root);
        return res;
    }

    void dfs(Node *root) {
        if (!root) return;
        res.push_back(root->val);
        for (auto c : root->children)
            dfs(c);
    }
};
// 非递归
/**
 * 执行用时:28 ms, 在所有 C++ 提交中击败了64.12%的用户
 * 内存消耗:11.2 MB, 在所有 C++ 提交中击败了72.09%的用户
 */
class Solution {
public:
    vector<int> preorder(Node *root) {
        vector<int> res;
        stack<Node *> stk;
        if (root) stk.push(root);
        while (stk.size()) {
            auto t = stk.top(); stk.pop();
            res.push_back(t->val);
            reverse(t->children.begin(), t->children.end());
            for (auto c : t->children) {
                if (c) stk.push(c);
            }
        }
        return res;
    }
};
  • Java
/**
 * 递归
 * 执行用时:1 ms, 在所有 Java 提交中击败了95.48%的用户
 * 内存消耗:39.6 MB, 在所有 Java 提交中击败了56.39%的用户
 */
public class Solution {
    List<Integer> res = new ArrayList<>();

    public List<Integer> preorder(Node root) {
        dfs(root);
        return res;
    }

    private void dfs(Node root) {
        if (root == null) return;
        res.add(root.val);
        if (root.children != null)
            for (Node child : root.children)
                dfs(child);
    }
}
/**
 * 非递归
 * 执行用时:5 ms, 在所有 Java 提交中击败了16.09%的用户
 * 内存消耗:39.7 MB, 在所有 Java 提交中击败了38.13%的用户
 */
public class Solution {
    public List<Integer> preorder(Node root) {

        List<Integer> res = new ArrayList<>();
        Deque<Node> stk = new ArrayDeque<>();
        if (root != null) stk.push(root);
        while (!stk.isEmpty()) {
            Node t = stk.pop();
            res.add(t.val);
            if (t.children != null) {
                Collections.reverse(t.children);
                for (Node child : t.children)
                    if (child != null)
                        stk.push(child);
            }
        }
        return res;
    }
}

Leetcode 0590 N叉树的后序遍历

问题描述

分析

  • N叉树的前序遍历:从左到右遍历该根对应的孩子,然后遍历根

  • 思路:类似于二叉树的后续遍历,我们可以按如下方式解决:

    (1) 按照 根 子节点n ... 子节点2 子节点1 方式遍历

    (2) 翻转得到结果

代码

  • C++
// 递归
/**
 * 执行用时:20 ms, 在所有 C++ 提交中击败了87.55%的用户
 * 内存消耗:11.3 MB, 在所有 C++ 提交中击败了61.37%的用户
 */
class Solution {
public:
    vector<int> res;

    vector<int> postorder(Node *root) {
        dfs(root);
        return res;
    }

    void dfs(Node *root) {
        if (!root) return;
        for (auto c : root->children)
            dfs(c);
        res.push_back(root->val);
    }
};
// 非递归
/**
 * 执行用时:24 ms, 在所有 C++ 提交中击败了72.41%的用户
 * 内存消耗:11.2 MB, 在所有 C++ 提交中击败了79.58%的用户
 */
class Solution {
public:
    vector<int> postorder(Node *root) {
        vector<int> res;
        stack<Node *> stk;
        if (root) stk.push(root);
        while (stk.size()) {
            auto t = stk.top(); stk.pop();
            res.push_back(t->val);
            for (auto c : t->children) {
                if (c) stk.push(c);
            }
        }
        reverse(res.begin(), res.end());
        return res;
    }
};
  • Java
/**
 * 递归
 * 执行用时:1 ms, 在所有 Java 提交中击败了96.32%的用户
 * 内存消耗:39.7 MB, 在所有 Java 提交中击败了56.65%的用户
 */
public class Solution {
    List<Integer> res = new ArrayList<>();

    public List<Integer> postorder(Node root) {
        dfs(root);
        return res;
    }

    private void dfs(Node root) {
        if (root == null) return;
        if (root.children != null)
            for (Node child : root.children)
                dfs(child);
        res.add(root.val);
    }
}
/**
 * 非递归
 * 执行用时:4 ms, 在所有 Java 提交中击败了40.11%的用户
 * 内存消耗:39.4 MB, 在所有 Java 提交中击败了47.68%的用户
 */
public class Solution {
    public List<Integer> postorder(Node root) {

        List<Integer> res = new ArrayList<>();
        Deque<Node> stk = new ArrayDeque<>();
        if (root != null) stk.push(root);
        while (!stk.isEmpty()) {
            Node node = stk.pop();
            res.add(node.val);
            if (node.children != null)
                for (Node child : node.children)
                    if (child != null)
                        stk.push(child);
        }
        Collections.reverse(res);
        return res;
    }
}

Leetcode 0429 N叉树的层序遍历

问题描述

分析

  • N叉树的层序遍历:逐层地,从左到右访问所有节点

代码

  • C++
/**
 * 执行用时:20 ms, 在所有 C++ 提交中击败了84.18%的用户
 * 内存消耗:11.4 MB, 在所有 C++ 提交中击败了97.76%的用户
 */
class Solution {
public:
    vector<vector<int>> levelOrder(Node *root) {

        vector<vector<int>> res;
        if (!root) return res;
        queue<Node *> q;
        q.push(root);
        while (q.size()) {
            int len = q.size();
            vector<int> line;
            while (len--) {
                auto t = q.front(); q.pop();
                line.push_back(t->val);
                for (auto c : t->children)
                    q.push(c);
            }
            res.push_back(line);
        }
        return res;
    }
};
  • Java
/**
 * Created by WXX on 2021/2/28 18:04
 * 执行用时:4 ms, 在所有 Java 提交中击败了45.55%的用户
 * 内存消耗:39.3 MB, 在所有 Java 提交中击败了70.71%的用户
 */
public class Solution {

    public List<List<Integer>> levelOrder(Node root) {

        List<List<Integer>> res = new ArrayList<>();
        if (root == null) return res;
        Queue<Node> q = new LinkedList<>();
        q.add(root);
        while (!q.isEmpty()) {
            int len = q.size();
            List<Integer> line = new ArrayList<>();
            while (len-- != 0) {
                Node t = q.remove();
                line.add(t.val);
                if (t.children != null)
                    for (Node c : t.children)
                        q.add(c);
            }
            res.add(line);
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值