力扣二叉树专题(三)-N叉树的前序、后序遍历 翻转二叉树 前中后序遍历 DFS BFS 递归法 迭代法 多种方法C++实现 总结

文章目录

  • 一、N叉树的前序遍历与后序遍历
    • 1. n叉树的前序遍历-题589
    • 2. n叉树的后序遍历-题590
  • 二、翻转二叉树-题226

力扣二叉树专题(一)介绍了二叉树的深度优先遍历,前中后序的递归、迭代、统一迭代实现。

力扣二叉树专题(二)介绍了二叉树的广度优先遍历中的层序遍历,从左到右一层一层的去遍历二叉树。

对于二叉树的遍历总共8种:

  • 前序遍历
  • 中序遍历
  • 后续遍历
  • 深度优先搜索(DFS)
  • 宽度优先搜索(BFS)
  • Morris(莫里斯)的前中后3种遍历方式

N叉树的前后序遍历和翻转二叉树还是用层序遍历,每道题都用了DFS、BFS

一、N叉树的前序遍历与后序遍历

可以参考二叉树的前序遍历和后序遍历的迭代法和递归法的实现

1. n叉树的前序遍历-题589

递归法: 要注意的是,遍历子树时,从左边开始,即子节点的第一个开始

class Solution {
public:
    //1.递归法
    void order(Node* cur, vector<int>& result)
    {
        if(cur==NULL) return;
        result.push_back(cur->val);
        for(int i=0;i<cur->children.size();i++)
        {
            if(cur->children[i]) order(cur->children[i], result);
        }
    }
    vector<int> preorder(Node* root) {
        vector<int> result;
        order(root, result);//depth可以不传 没啥用
        return result;
    }
};

迭代法: 用栈访问节点

注意:

  1. 无论是二叉树还是N叉树,先处理根节点,先访问再处理
  2. 对于二叉树,子节点入栈顺序是先右节点,再左节点,因为栈特点是先进后出
class Solution {
public:
    //迭代法
    vector<int> preorder(Node* root)
    {
        vector<int> result;
        stack<Node*> st;
        if(root==NULL) return result;

        //根节点
        st.push(root);
        while(!st.empty())
        {
            Node* cur = st.top();
            st.pop();
            result.push_back(cur->val);
            for(int i=0;i<cur->children.size();i++)
            {
            	//从后面开始存 栈先进后出
                if(cur->children[cur->children.size()-1-i]) st.push(cur->children[cur->children.size()-1-i]);
            }
        }
        return result;
    }
};

2. n叉树的后序遍历-题590

在前序遍历的基础上调整一下代码顺序

递归法: 中右左顺序递归,最后反转一下数组

class Solution {
public:
    //递归法
    void order(Node* cur, vector<int>& result)
    {
        if(!cur) return;
        result.push_back(cur->val);
        for(int i=0;i<cur->children.size();i++)
        {
            order(cur->children[cur->children.size() - 1 - i], result);//中右左
        }
    }

    vector<int> postorder(Node* root) {
        vector<int> result;
        order(root, result);
        reverse(result.begin(), result.end());
        return result;
    }
};

迭代法: 入栈时,中右左顺序,最后反转一下数组

class Solution {
public:
    //迭代法
    vector<int> postorder(Node* root)
    {
        vector<int> result;
        stack<Node*> st;
        if(!root) return result;//空树

        st.push(root);//根节点先处理
        while(!st.empty())
        {
            Node* cur = st.top();
            st.pop();
            result.push_back(cur->val);
            for(int i=0; i<cur->children.size(); i++)
            {
                if(cur->children[i]) st.push(cur->children[i]);
            }
        }
        reverse(result.begin(), result.end());
        return result;
    }
};

二、翻转二叉树-题226

DFS 前序遍历-递归法 确定三个条件(参数及返回值;递归结束条件;递归单次操作)
首先,判断节点是否为空,为空则空树或是遍历结束;
然后,如果节点有子节点(只有左子节点、只有右子节点、有左右节点)都进行交换;
最后,递归,分别传入节点的左右子节点

class Solution {
public:
    //递归法 前序
    TreeNode* invertTree(TreeNode* root) {
        if(root==nullptr) return root;
        swap(root->left, root->right);//中
        invertTree(root->left);//左
        invertTree(root->right);//右
        return root;
    }
};

DFS的中序和后序的递归实现把上面的代码调整一下顺序就好了

DFS 前序遍历-迭代法 栈

class Solution {
public:
    //DFS 前序遍历-迭代法 栈
    TreeNode* invertTree(TreeNode* root)
    {
        stack<TreeNode*> st;
        if(root) st.push(root);
        while(!st.empty())
        {
            TreeNode* cur = st.top();//中
            st.pop();
            swap(cur->left, cur->right);
            if(cur->left) st.push(cur->left);//左
            if(cur->right) st.push(cur->right);//右
        }
        return root;
    }
};

DFS 后序遍历-迭代法 栈

class Solution {
public:
    //DFS 后序遍历-迭代法 栈
    TreeNode* invertTree(TreeNode* root)
    {
        stack<TreeNode*> st;
        if(root) st.push(root);
        while(!st.empty())
        {
            TreeNode* cur = st.top();//中
            st.pop();
            swap(cur->left, cur->right);
            if(cur->right) st.push(cur->right);//右
            if(cur->left) st.push(cur->left);//左
        }
        return root;
    }
};

DFS 中序遍历-统一迭代法 栈 中节点要标记 先访问再处理

class Solution {
public:
    //DFS 中序遍历-统一迭代法 栈
    TreeNode* invertTree(TreeNode* root)
    {
        stack<TreeNode*> st;
        if(root) st.push(root);
        while(!st.empty())
        {
            TreeNode* cur = st.top();
            if(cur)//先访问节点
            {
                st.pop();
                if(cur->right) st.push(cur->right);//右
                st.push(cur);///中
                st.push(NULL);//标记
                if(cur->left) st.push(cur->left);//左;
            }
            else//再处理节点
            {
                st.pop();//弹出空节点
                cur = st.top();//处理空节点的下一个节点
                st.pop();
                swap(cur->left, cur->right);
            }
        }
        return root;
    }
};

BFS 层序遍历-迭代法 队列

class Solution {
public:
    //迭代法
    TreeNode* invertTree(TreeNode* root)
    {
        queue<TreeNode*> que;
		if(root) que.push(root);
        while(!que.empty())
        {
            TreeNode* cur = que.front();
            que.pop();
            swap(cur->left, cur->right);//中
            if(cur->left) que.push(cur->left);//左
            if(cur->right) que.push(cur->right);//右
        }
        return root;
    }
};

总结

  1. 递归法,三要素,确定参数及返回值、确定递归结束条件、确定递归单次操作
  2. 迭代法,前中后序遍历,用栈;前后序,先访问再处理,先处理中节点;中序,借助指针,指针访问节点,栈处理节点,先处理再访问
  3. 统一迭代法,把前中后序的迭代统一实现,中节点用空指针标记,先访问再处理,用栈
  4. 层序遍历,递归法实现时注意三要素和深度控制;迭代法实现时,用队列
  5. 递归法和迭代法,以下是搬运代码随想录的内容,方便之后回顾
  • 从时间复杂度上其实迭代法和递归法差不多(在不考虑函数调用开销和函数调用产生的堆栈开销),但是空间复杂度上,递归开销会大一些,因为递归需要系统堆栈存参数返回值等等。
  • 递归更容易让程序员理解,但收敛不好,容易栈溢出。
  • 递归是方便了程序员,难为了机器(各种保存参数,各种进栈出栈)。
  • 在实际项目开发的过程中我们是要尽量避免递归!因为项目代码参数、调用关系都比较复杂,不容易控制递归深度,甚至会栈溢出。

你可能感兴趣的:(LeetCode,c++,leetcode,dfs,bfs,深度优先遍历)