代码随想录Day15 | 层序遍历,翻转二叉树,对称二叉树

代码随想录Day15 | 层序遍历,翻转二叉树,对称二叉树

  • 层序遍历
  • 翻转二叉树
  • 对称二叉树

层序遍历

文档讲解:代码随想录
视频讲解:
状态

层序遍历的原理就是利用队列来模拟节点的入和出的问题。从头节点入开始,之后每当一个节点出队列,那么就从队尾加入其左子结点和右子节点。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector> levelOrder(TreeNode* root) {
        queue treeque;
        //压入头节点
        if(root != nullptr) treeque.push(root);
        //返回数组
        vector> res;
        while(!treeque.empty())
        {
            //记录当前层的节点树
            int temp = treeque.size();
            //存储当前层的节点数组
            vector vec;
            for(int i =0;ival);
                treeque.pop();
                //压入当前节点的左节点和右节点
                if(cur->left) treeque.push(cur->left);
                if(cur->right) treeque.push(cur->right);
            }
            //将当前层的结果压入到返回数组中
            res.push_back(vec);
        }
        return res;
    }
};
  1. 递归法
  • 递归参数和返回值:当前节点,返回结果的数组以及当前的层数
  • 终止条件:当前节点为空节点时,结束
  • 递归逻辑:
//初始化,如果当前数组大小和层数相等,则先加入一个数组,该数组用来存放当前层的节点
if(res.size() == loc) res.push_back(vector());
//在数组中的当前层加入当前节点
res[loc].push_back(cur->val);
//递归处理左子节点和右子节点
function1(cur->left,res,loc+1);
function1(cur->right,res,loc+1);

具体函数

void ResTree(TreeNode* cur,vector>& res,int dep)
    {
        //递归终止条件
        if(cur == nullptr) return ;
        //初始化当前层的存储数组
        if(res.size()==dep) res.push_back(vector());
        //存入当前值
        res[dep].push_back(cur->val);
        //递归为其左节点和右节点
        ResTree(cur->left,res,dep+1);
        ResTree(cur->right,res,dep+1);
    }
vector> levelOrder(TreeNode* root) {
        int dep = 0;
        vector> res;
        ResTree(root,res,dep);
        return res;
    }

翻转二叉树

文档讲解:代码随想录
视频讲解:
状态:层序遍历

当队列头元素存在左节点或者右节点是,交换。然后再压入。当然也可以先压入再交换。交换相当于是对中节点的操作。

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        queue treeque;
        if(root) treeque.push(root);

        while(!treeque.empty())
        {
            int tempsize = treeque.size();
            
            for(int i=0;ileft||cur->right)
                {
                    swap(cur->left,cur->right);
                }

                if(cur->left) treeque.push(cur->left);
                if(cur->right) treeque.push(cur->right);
            }
        }
        return root;
    }
};
  1. 递归
  • 函数参数,树的根节点
  • 终止条件:翻转节点为空
  • 单层逻辑:翻转该节点的左和右,然后调用该函数继续对其现在的左节点和右节点进行翻转。
swap(...);
func1(left);
func1(right);

具体程序

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root==nullptr) return root;
        invertTree(root->left); //左
        invertTree(root->right); //右  -- 上两步可以看作是遍历获取
        swap(root->left,root->right); //中
        return root;
    }
};

交换要么在两节点递归之前,要么在两节点递归之后。否则可能会出现一方没有交换的情况。交换的操作不应该在遍历操作之间,两者是分开进行的。
3. 迭代

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        stack treestk;
        if(root) treestk.push(root);

        while(!treestk.empty())
        {
            //记录中节点
            TreeNode* cur = treestk.top();
            //弹出中节点
            treestk.pop();

            //遍历
            //压入右节点
            if(cur->right) treestk.push(cur->right);
            //压入左节点
            if(cur->left) treestk.push(cur->left);

            //交换操作
            swap(cur->left,cur->right);
        }
        return root;
    }
};

对称二叉树

文档讲解:代码随想录
视频讲解:
状态:×

比较的其实是两棵子树是否是翻转的,
对于左子树可以采用中左右的方式存入到队列中
对于右子树可以采用中右左的方式存入到队列中。
如果队列的每个元素相等,说明true。

如果采用递归法,应当使用后序遍历,即从子结点开始判断是否相等。我们需要确定

  1. 参数和返回值:参数就是左子树和右子树对应的节点,返回值就是true或者false
  2. 终止条件:就是返回bool的情况
//对应左节点和右节点为空 true
if (left == nullptr && right == nullptr) return true;
//对应左节点和右节点有一个不为空 false
else if (left != nullptr && right == nullptr) return false;
else if (left == nullptr && right != nullptr) return false;
//对应左节点和右节点都不为空,但值不等 false
else if (left->val != right->val) return false;
  1. 单层逻辑
    就是处理当前对应节点相同的情况,当前节点就是中节点,中节点的值相同了,还需要考虑以其为父节点的子树对应值是否相同(递归的调用),最后结合在一起才是最终的中节点。
bool out = compare(left->left,right->right);
bool inside = compare(left->right,right->left);
bool mid = true && out && inside; //true代表中节点为true
return mid;

迭代法:注意加入元素的顺序,因为每次比较是取容器前两个元素比较,所以加入的顺序应当是相互对应的,比如

  • 加入左子树左节点,那么下一个就加入右子树右节点,然后才是左子树右节点,右子树左节点

你可能感兴趣的:(算法)