遍历二叉树
三种递归遍历
前序遍历
根——左——右
void preorder(TreeNode *root, vector<int> &path)
{
if(root == nullptr) return;
path.push_back(root->val);
preorder(root->left, path);
preorder(root->right, path);
}
中序遍历
左——根——右
void inorder(TreeNode *root, vector<int> &path)
{
if(root == nullptr) return;
inroder(root->left,path);
path.push_back(root->val);
inorder(root->right,path);
}
后序遍历
左——右——根
void postorder(TreeNode *root, vector<int> &path)
{
if(root == nullptr) return;
postorder(root->left,path);
postorder(root->right,path);
path.push_back(root->val);
}
三种非递归遍历
前序遍历
class Solution
{
public:
vector<int> preorderTraversal(TreeNode* root)
{
vector<int> path;
if(root == nullptr) return path;
stack<TreeNode*> s;
TreeNode *p = root;
while(p || !s.empty())
{
if(p) //当左结点不为空时
{
path.push_back(p->val); //访问当前结点(父结点)
s.push(p); //入栈
p = p->left; //指向下一个左结点
}
else //当左结点为空时
{
p = s.top();
s.pop(); //出栈
p = p->right; //指向右结点
}
}
return path;
}
};
中序遍历
class Solution
{
public:
vector<int> inorderTraversal(TreeNode* root)
{
vector<int> path;
if(root == nullptr) return path;
stack<TreeNode*> s;
TreeNode *p = root;
while(p || !s.empty())
{
if(p) //当左结点不为空时
{
s.push(p); //入栈
p = p->left; //指向下一个左结点
}
else //当左结点为空时
{
p = s.top();
path.push_back(p->val); //访问栈顶元素(父结点)
s.pop(); //出栈
p = p->right; //指向右结点
}
}
return path;
}
};
后序遍历
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
if(!root) return res;
stack<TreeNode*> s;
s.push(root);
while(!s.empty()){
TreeNode* temp = s.top();
s.pop();
res.push_back(temp->val);
if(temp->left) s.push(temp->left);
if(temp->right) s.push(temp->right);
}
reverse(res.begin(),res.end()); //将前序遍历翻转即可
return res;
}
};
//
vector<int> postorderTraversal(TreeNode* root)
{
vector<int> result;
stack<TreeNode*> s;
if(root== nullptr) return result;
TreeNode* p; //当前结点指针
TreeNode* pre = nullptr; //用于记录上一次访问的结点
s.push(root); //根结点指针入栈
while(!s.empty())//不为空时才会入栈,故p不可能为nullptr,无需像之前加p的判断
{
p = s.top(); // 指向栈顶元素
bool temp1 = p->left == nullptr && p->right == nullptr; //如果当前结点为叶子结点
bool temp2 = pre != nullptr && (pre == p->left || pre == p->right); //或者当前结点的左结点和右结点都已被访问过了(若pre=p->left说明右结点为空,因为栈中按照根右左这样的顺序入栈,根左这种结构才能出现这种情况)
if(!temp1 && !temp2)//如果不是上面两种情况,直接入栈
{
//先将右结点入栈,再将左结点入栈,这样可以保证之后访问时先访问左结点在访问右结点
if(p->right) s.push(p->right); //右结点入栈
if(p->left) s.push(p->left); //左结点入栈
}
else
{
result.push_back(p->val); //访问顺序:左、右、根
s.pop();
pre = p; //保存刚刚访问过的结点
}
}
return result;
}
从上到下打印二叉树
1. 顺序打印
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> levelOrder(TreeNode* root) {
vector<int> result;
if(root==NULL) return result;
queue<TreeNode*> dq;
dq.push(root);
while(!dq.empty()){
TreeNode* temp=dq.front(); //当前根节点
dq.pop();
result.push_back(temp->val); //加入对列
//将当前结点的左右子结点入队
if(temp->left) dq.push(temp->left);
if(temp->right) dq.push(temp->right);
}
return result;
}
};
2. 按层打印
a. 递归解法 O(n), O(1)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> ans;
pre(root,0,ans);
return ans;
}
void pre(TreeNode* root,int depth,vector<vector<int>> &ans){
if(!root) return; //递归出口
if(depth>=ans.size()) ans.push_back(vector<int> {}); //在下一层时,增加空容器(因为事先不知道树的层数,故要一边遍历,一边增加容器大小)
ans[depth].push_back(root->val); //将元素值push进第level层的容器(索引从0开始)
pre(root->left,depth+1,ans);
pre(root->right,depth+1,ans);
}
};
b. 迭代解法 O(n),O(1)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
if(!root) return res;
queue<TreeNode*> q;
q.push(root);
while(!q.empty()){
vector<int> tmp; //用来保存每一层的节点
int len=q.size(); //获取当前队列长度,即可确定当前层的节点个数
for(int i=0;i<len;i++){ //遍历该层结点,并将下一层结点入队
TreeNode* t=q.front(); //访问当前结点
q.pop(); //出队
tmp.push_back(t->val);
//将当前结点的左右子结点入队
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
}
res.push_back(tmp);
}
return res;
}
};
3. 之字形打印
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
//分析:广度优先遍历(??感觉遍历顺序是先序遍历,为深度优先遍历),用一个bool记录是从左到右还是从右到左,每一层结束就翻转一下
//用level-order遍历,用奇数层偶数层判断,偶数层时反向存数
class Solution {
private:
vector<vector<int>> res;
public:
vector<vector<int>> levelOrder(TreeNode* root) {
dfs(root,0);
return res;
}
void dfs(TreeNode* root,int layer){
if(root==NULL) return;
if(res.size()<layer+1) res.push_back({});
if(layer&1) res[layer].insert(res[layer].begin(),root->val); //增加一个层数奇偶性的判断,奇数层反向输入
else res[layer].push_back(root->val);
//将当前结点的左右子结点入队
dfs(root->left,layer+1);
dfs(root->right,layer+1);
}
};
/*
方法二:迭代法
按level order遍历,偶数层时翻转一下(可以用一bool型变量,每一层反号一次)
*/
class Solution
{
public:
vector<vector<int>> zigzagLevelOrder(TreeNode *root)
{
vector<vector<int> > res;
if (root == nullptr) return res;
queue<TreeNode*> q;
q.push(root); //根结点入队
bool right_to_left = false;
while (!q.empty())
{
vector<int> level;
int size = q.size(); //当前层的结点数
for (int i = 0; i < size; ++i) //遍历该层结点,并将下一层结点入队
{
TreeNode *node = q.front();
level.push_back(node->val); //访问当前结点
q.pop(); //出队
//将当前结点的左右子结点入队
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
//下一层的结点排在上一层结点之后
}
if(right_to_left) reverse(level.begin(), level.end()); //反序
res.push_back(level);
right_to_left = !right_to_left;
}
return res;
}
};
垂序遍历
/* 掌握
问题:二叉树的垂直遍历
方法:层序遍历,并给每个结点赋上列号(对于每列元素而言,层序遍历访问的先后顺序满足垂直遍历规律)
把根节点给个序号0,然后开始层序遍历,
凡是左子节点则序号减1,右子节点序号加1,
这样我们可以通过序号来把相同列的节点值放到一起
*/
class Solution
{
public:
vector<vector<int>> verticalOrder(TreeNode* root)
{
vector<vector<int>> res;
if (!root) return res;
map<int, vector<int>> m; //构建存储<序号,遍历序列>对的map
queue<pair<int, TreeNode*>> q; //构建存储<序号,结点>对的队列
q.push({0, root}); //根结点入队,根结点序号设为0
while (!q.empty()) //层序遍历
{
auto a = q.front();
m[a.first].push_back(a.second->val); //访问当前结点,将结点值push到相同列的容器中
q.pop(); //出队
//将下一层结点入队
if (a.second->left) q.push( {a.first - 1, a.second->left} ); //左结点序号减一
if (a.second->right) q.push( {a.first + 1, a.second->right} ); //右结点序号加一
//下一层的结点排在上一层结点之后
}
for (auto mi : m) //将map中遍历序列按顺序push到结果容器中(map内部会自动排序,序号从小到大排列遍历序列)
{
res.push_back(mi.second);
}
return res;
}
};