【力扣-二叉树】1、二叉树的遍历

159 阅读3分钟

「这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战

二叉树的遍历方式

  • 深度优先遍历(使用栈)
  • 广度优先遍历(使用队列)

深度优先遍历

  • 前序遍历(中左右)
  • 中序遍历(左中右)
  • 后序遍历(左右中) :上面的三种遍历方式可以使用递归法也可以使用迭代法

递归遍历

/*
    递归遍历:
        递归算法三要素:
            1、确定递归函数的参数与返回值
                (递归中需要处理的参数 与 每次递归结束需要返回的结果值)
            2、确定终止条件
                (递归算法最常见的错误就是栈溢出,原因是终止条件没有写正确)
            3、确定单层递归的逻辑
                (每层递归要处理的逻辑)
    
    二叉树的递归遍历:
        1、前序遍历
        2、中序遍历
        3、后序遍历
*/
struct TreeNode
{
    int val;
    TreeNode *left;
    TreeNode *right;

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

class Traversal
{
public:
    // 前序遍历
    void preTraversal(TreeNode *node, vector<int> &vec)
    {
        // 终止条件
        if (node == NULL)
        {
            return;
        }
        // 递归逻辑
        vec.push_back(node->val);
        preTraversal(node->left, vec);
        preTraversal(node->right, vec);
    }
    vector<int> preTraversalResult(TreeNode *root)
    {
        vector<int> vec;
        preTraversal(root, vec);
        return vec;
    }

    // 中序遍历
    void midTraversal(TreeNode *node, vector<int> &vec)
    {
        if (node == NULL)
        {
            return;
        }
        midTraversal(node->left, vec);
        vec.push_back(node->val);
        midTraversal(node->right, vec);
    }
    vector<int> midTraversalResult(TreeNode *root)
    {
        vector<int> vec;
        midTraversal(root, vec);
        return vec;
    }

    // 后续遍历
    void postTraversal(TreeNode *node, vector<int> &vec)
    {
        if (node == NULL)
        {
            return;
        }
        postTraversal(node->left, vec);
        postTraversal(node->right, vec);
        vec.push_back(node->val);
    }

    vector<int> postTraversalResult(TreeNode *root)
    {
        vector<int> vec;
        postTraversal(root, vec);
        return vec;
    }
};

迭代遍历

class Traversal
{
public:
    // 根据栈的特性

    // 前序遍历
    // 遍历过程:中 左 右
    // 根节点入栈
    // 遍历子树的过程中先将右子树入栈,在将左子树入栈
    // 这样出栈的时候就是 : 根节点出栈 -- 左子树出栈 -- 右子树出栈
    vector<int> preorderTraversal(TreeNode *root)
    {
        stack<TreeNode *> st;
        vector<int> result;
        if (root == NULL)
        {
            return result;
        }

        // 先将根节点入栈
        st.push(root);
        while (!st.empty())
        {
            // 指针指向栈顶节点
            TreeNode *cur = st.top();
            // 栈顶节点出栈(即每棵树的根节点)
            st.pop();
            result.push_back(cur->val);
            // 先将右子树入栈
            if (cur->right != NULL)
            {
                st.push(cur->right);
            }
            // 左子树入栈
            if (cur->left != NULL)
            {
                st.push(cur->left);
            }
        }
        return result;
    }

    // 后序遍历
    // 后续遍历的过程为 左右中,所以可以由前序遍历变化得到
    // 变化过程: 中左右 -> 中右左 ->(反转)左右中
    // 所以对于前序遍历的入栈过程:从 中右左 -> 中左右 即可
    vector<int> postorderTraversal(TreeNode *root)
    {
        stack<TreeNode *> st;
        vector<int> result;
        if (root == NULL)
        {
            return result;
        }

        // 根节点入栈
        st.push(root);
        while (!st.empty())
        {
            // 获取栈顶节点,并出栈
            TreeNode *cur = st.top();
            st.pop();
            result.push_back(cur->val);
            // 左子树入栈
            if (cur->left)
            {
                st.push(cur->left);
            }
            // 右子树入栈
            if (cur->right)
            {
                st.push(cur->right);
            }
        }
        reverse(result.begin(), result.end());
        return result;
    }

    // 中序遍历
    // 遍历过程:左 中 右
    // 先将最左侧子树的左子树... 入栈
    vector<int> midorderTraversal(TreeNode *root)
    {
        stack<TreeNode *> st;
        vector<int> result;

        TreeNode *cur = root;
        // 当前节点的左子树非空或者栈非空
        while (cur != NULL || !st.empty())
        {
            if (cur != NULL)
            {
                st.push(cur);
                cur = cur->left;
            }
            else
            {
                // 左子树出栈
                TreeNode *node = st.top();
                st.pop();
                result.push_back(node->val); // 中
                if (node->right)
                {
                    st.push(node->right); // 右
                }
            }
        }
        return result;
    }
};

广度优先遍历

  • 层次遍历(迭代法)

代码

class Traversal
{
public:
    vector<vector<int>> levelOrder(TreeNode *root)
    {
        queue<TreeNode *> que;
        if (root != NULL)
        {
            que.push(root);
        }
        vector<vector<int>> result;
        while (!que.empty())
        {
            int size = que.size();
            vector<int> vec;
            // 这里一定要使用固定大小的size,不要使用que.size()
            // 因为que.size()是不断变化的
            for (int i = 0; i < size; i++)
            {
                TreeNode *node = que.front();
                que.pop();
                vec.push_back(node->val);
                if (node->left)
                {
                    que.push(node->left);
                }
                if (node->right)
                {
                    que.push(node->right);
                }
            }
            result.push_back(vec);
        }

        return result;
    }
    // 反转数组元素
    void reverseVector(vector<vector<int>> &result)
    {
        int left = 0, right = result.size() - 1;
        while (left < right)
        {
            vector<int> tmp = result[left];
            result[left] = result[right];
            result[right] = tmp;
        }
    }
};