层序遍历
层次遍历
题目链接:102. 二叉树的层序遍历
思路及代码实现
层次遍历类似于图的广度优先搜索,用队列实现;
从根结点开始入队,每次从队头访问一个结点,同时将其左右孩子添加到队尾;
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
queue<TreeNode*> que;
if(root != NULL) que.push(root);
while(!que.empty()){
int size = que.size(); // 当前层的结点数
vector<int> vec;
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;
}
};
递归法
代码随想录上还提供了递归法,但是没有上面这种算法能更好地体现广度优先搜索的思想;但是递归法代码更简单,逻辑更清晰,可能是我先入为主了。
下面让我们来分析下递归法:
参数要包括当前树结点、引用的结果数组、当前层数;无返回值;
停止条件为所有结点所有层均访问完毕;
每层的逻辑为:将当前树结点数值存入结果数组,递归下一层,结点分别为当前结点的左、右孩子;
class Solution {
public:
void order(TreeNode* cur, vector<vector<int>>& result, int depth){
if(cur == NULL) return;
if(result.size() == depth) result.push_back(vector<int> ()); // 补个空一维数组
result[depth].push_back(cur->val); // result有depth层吗?故补上一句
order(cur->left, result, depth + 1);
order(cur->right, result, depth + 1);
}
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result; // 谁也不知道树多少层,现在结果数组为空
int depth = 0;
order(root, result, depth);
return result;
}
};
226.翻转二叉树
题目链接:226. 翻转二叉树
翻转二叉树,只需要翻转每个结点的左右孩子即可,故选择一种遍历方法,然后对其左右孩子进行翻转;其中,中序遍历的递归法不行,会出现翻转两次的情况;可以选择前序、中序遍历,或者层次遍历。
前序遍历
(后序遍历与前序遍历类似)
递归法
class Solution {
public:
void traversal(TreeNode* cur){
if(cur == NULL) return;
swap(cur->left, cur->right);
traversal(cur->left);
traversal(cur->right);
}
TreeNode* invertTree(TreeNode* root) {
traversal(root);
return root;
}
};
递归法逻辑比较简单,容易想到。
迭代法
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
stack<TreeNode*> st;
if(root == NULL) return root;
st.push(root);
while(!st.empty()){
TreeNode* node = st.top();
st.pop();
swap(node->left, node->right);
if(node->left) st.push(node->left);
if(node->right) st.push(node->right);
}
return root;
}
};
层次遍历
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
queue<TreeNode*> que;
if(root == NULL) return root;
que.push(root);
while(!que.empty()){
TreeNode* node = que.front();
que.pop();
swap(node->left, node->right);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
return root;
}
};
小结
无论是前序遍历(后序遍历)的递归法、迭代法,还是层次遍历,时间空间的占用情况都差不多,其中递归法是逻辑最简单的,但是使用递归时一定注意递归三要素,递归容易出现奇奇怪怪的问题。
101.对称二叉树
题目链接:101. 对称二叉树
递归法
查看过解析后发现,递归法使用后序遍历最佳。
什么时候考虑使用后序遍历呢?当需要收集孩子信息向上一层返回的时候,选择后序遍历。
class Solution {
public:
bool compare(TreeNode* le, TreeNode* ri){
if(le == NULL && ri != NULL) return false;
else if(le != NULL && ri == NULL) return false;
else if(le == NULL && ri == NULL) return true;
else if(le->val != ri->val) return false;
else{
bool exside = compare(le->left, ri->right);
bool inside = compare(le->right, ri->left);
return (exside && inside);
}
}
bool isSymmetric(TreeNode* root) {
return compare(root->left, root->right);
}
};
迭代法
利用队列,每次成对入队,成对出队,判断是否对称。
class Solution {
public:
bool isSymmetric(TreeNode* root) {
queue<TreeNode*> que;
que.push(root->left);
que.push(root->right);
while(!que.empty()){
TreeNode* le = que.front(); que.pop();
TreeNode* ri = que.front(); que.pop();
if(!le && !ri) continue;
if(!le || !ri || (le->val != ri->val)) return false;
que.push(le->left);
que.push(ri->right);
que.push(le->right);
que.push(ri->left);
}
return true;
}
};