二叉树定义:
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int val) : val(val), left(nullptr), right(nullptr) {}
};
总结递归三部曲:
1.确定递归函数的参数和返回值
2.确定终止条件
3.确定单层循环逻辑
前序递归遍历代码:
//前序遍历
void traversal(TreeNode* cur,vector& vec){
if(cur == Null) return;
vec.push_back(cur->val);//中,当前访问节点值存入数组
traversal(cur->left,vec);//左
traversal(cur->right,vec);//右
}
vector preorderTraversal(TreeNode* root) {
vector result;//存放结果
traversal(root,result);
return result;
}
后中序遍历只需改变顺序。
思路:递归实际是个入栈的过程,二叉树的迭代遍历(非递归)就可以模拟入栈和出栈的过程进行遍历。
前序遍历:
遍历顺序中-左-右,迭代思路访问当前节点,接着把该节点右孩子先入栈再把左孩子入栈,再进行下一个节点访问。这样出栈顺序才会先访问左孩子再访问右孩子。
代码:
vector preorderTraversal(TreeNode* root) {
stack st;
vector result;
if(root == NULL) return result;
st.push(root);
while(!st.empty()){
//访问当前中间节点
TreeNode* cur = st.top();
result.push_back(cur->val);
st.pop();
if(cur->right) st.push(cur->right);//压入右孩子
if(cur->left) st.push(cur->left);//压入左孩子
}
return result;
}
后序迭代遍历和前序遍历类似,后序遍历顺序是左右中,中左右,则先访问中间节点,然后该节点入栈顺序是右左,出栈顺序左右。所以出栈顺序是中右左,再结果进行反转,则成左右中。
代码:
vector postorderTraversal(TreeNode* root) {
stack st;
vector result;
if(root == NULL) return result;
st.push(root);
while(!st.empty()){
//访问当前中间节点
TreeNode* cur = st.top();
result.push_back(cur->val);
st.pop();
if(cur->left) st.push(cur->left);//压入左孩子
if(cur->right) st.push(cur->right);//压入右孩子
}
reverse(result.begin(),result.end());
return result;
}
中序遍历
中序并不能像前序那样处理,因为中序可以看作是一直访问该节点的左子树一层层往下走,走到了该树最左边才往回访问中间节点然后是该节点右孩子的左子树,一层层往上。所以若用以上代码会导致代码复杂。
但是思路还是一样的,都是利用栈实现,一直把该节点的左孩子压入栈直到该树的最左边,再往回访问中间节点,再压入右子树,访问右子树最左边的节点,依次退栈。
代码:
vector inorderTraversal(TreeNode* root) {
vector result;
stack st;
TreeNode* cur = root;
while(cur != nullptr || !st.empty()){
if(cur != nullptr){//把该子树最左边的节点都压入栈
st.push(cur);
cur = cur->left;
}
else{
cur = st.top();
st.pop();
result.push_back(cur->val);//访问中间节点
cur = cur->right;//如果该节点有右孩子,则下一轮会继续压入以该节点为根节点的子树中的左孩子
//如果该节点没有右孩子,下一轮会访问(退栈)该节点的父节点
}
}
return result;
}
前中后序统一迭代法:一刷跳过