这道题掌握了基本概念后,代码很简单,但是一般大厂面试标明了只接受非递归法
首先分享一个图示法快速写出三种遍历的方法
任何算法的递归版本都可以改成非递归版本,因为函数递归调用其实质就是压栈的过程,那么我们完全可以使用堆栈来模拟这个过程。二叉树的遍历(递归法)很容易实现,本质是采用了栈帧的实现方式,函数调用就是压栈,函数求解就是出栈的过程,那么我们完全可以手动创建栈来模拟这个过程,按照指定遍历顺序迭代的访问二叉树的所有结点。
因为前序、中序、后序三种遍历方式在当前函数体内都是先调用f(root.left),再调用f(root.right),函数再往下逐层调用,直到f(root.left)返回为空时。所以三种遍历方式的切入点都是要先遍历到二叉树的最左子结点(root.left == null),在遍历的过程中将根节点入栈,出栈的时候访问当前根节点以及其右子二叉树。创建栈的作用主要就是能够让我们存储访问顺序的那些根节点,可以回溯的对二叉树进行访问。
关于递归和迭代的区别
请参考我的另外一篇博客
递归和迭代的区别
这里简述一下
- 递归是自身调用自身函数。递归一般是单个变量的不断使用
- 递归需要不断进栈出栈,内存消耗大
前序遍历
递归法
递归法重要的是写好递归函数
递归函数的三大要素
1.函数的返回类型及参数列表
2.函数的终止条件,不然会有栈溢出的危险
3.单层递归的逻辑
class Solution {
public:
void traversal(TreeNode *cur,vector<int>& res){
//需要注意这里是引用类型 不然返回空值
if(cur==NULL)
return;
res.push_back(cur->val);
traversal(cur->left,res);
traversal(cur->right,res);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
traversal(root,result);
return result;
}
};
迭代法
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> st;
TreeNode * p = root;
while(p||!st.empty()){
//当这两个都为空时表示遍历结束
while(p){
//结点不为空继续访问其左孩子 对于前序搜索先打印
result.push_back(p->val);
st.push(p);
p=p->left;
}
while(p==NULL&&!st.empty()){
p=st.top();//返回上一级
st.pop();//弹出
p=p->right;
}
}
return result;
}
};
中序遍历
递归法
class Solution {
public:
void traversal(TreeNode* p,vector<int>& res){
if(p==NULL)
return;
traversal(p->left,res);
res.push_back(p->val);
traversal(p->right,res);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
traversal(root,result);
return result;
}
};
迭代法
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> st;
TreeNode* p=root;//赋初值
while(p||!st.empty()){
while(p){
st.push(p);
p=p->left;
}
while(!p&&!st.empty()){
p=st.top();
result.push_back(p->val);
st.pop();
p=p->right;
}
}
return result;
}
};
后序遍历
递归法
lass Solution {
public:
void traversal(TreeNode* p,vector<int> &res){
if(p==NULL)
return;
traversal(p->left,res);
traversal(p->right,res);
res.push_back(p->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
traversal(root,result);
return result;
}
};
迭代法
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
TreeNode* p=root;
TreeNode* preVisite=NULL;
stack<TreeNode*> st;
while(p||!st.empty()){
if(p){
st.push(p);
p=p->left;
}
else{
p=st.top();
if(p->right==NULL||p->right==preVisite){
result.push_back(p->val);
preVisite=p;
st.pop();
p=NULL;
}
else{
p=p->right;
}
}
}
return result;
}
};
层序遍历
102. 二叉树的层序遍历
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
示例:
二叉树:[3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其层次遍历结果:
[
[3],
[9,20],
[15,7]
]
通过次数186,378提交次数294,634
层序遍历一般都用队列辅助解题,其具有先进先出的特点
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
if(root==NULL)
return res;
queue<TreeNode*> qt;
qt.push(root);
while(!qt.empty()){
vector<int> tmp;
int len=qt.size();
for(int i=0;i<len;i++){
TreeNode* p=qt.front();
qt.pop();
tmp.push_back(p->val);
if(p->left) qt.push(p->left);
if(p->right) qt.push(p->right);
}
res.push_back(tmp);
}
return res;
}
};
103. 二叉树的锯齿形层次遍历
给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
例如:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回锯齿形层次遍历如下:
[
[3],
[20,9],
[15,7]
]
通过次数67,778提交次数123,485
class Solution {
public:
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
vector<vector<int>> res;
if(root==NULL)
return res;
queue<TreeNode*> qu;
qu.push(root);
bool lr=true;
while(!qu.empty()){
int len=qu.size();
vector<int> tmp(len,0);
for(int i=0;i<len;i++){
TreeNode* p=qu.front();
qu.pop();
lr?(tmp[i]=p->val):(tmp[len-i-1]=p->val);
if(p->left)
{
qu.push(p->left);
}
if(p->right)
{
qu.push(p->right);
}
}
res.push_back(tmp);
lr=!lr;
}
return res;
}
};