递归三要素
-
确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
-
确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
-
确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。
LeetCode链接
144.二叉树的前序遍历
145.二叉树的后序遍历
94.二叉树的中序遍历
1.递归遍历二叉树
- 前中后序 递归遍历二叉树
class Solution {
public:
// 前序
void preOrder(TreeNode* node, vector<int> &result){
if(node==NULL) return;
result.push_back(node->val);
preOrder(node->left, result);
preOrder(node->right, result);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
preOrder(root, result);
return result;
}
// 中序
void inOrder(TreeNode* node, vector<int> &result){
if(node==NULL) return;
inOrder(node->left, result);
result.push_back(node->val);
inOrder(node->right, result);
}
// 后序
void postOrder(TreeNode* node, vector<int> &result){
if(node==NULL) return;
postOrder(node->left, result);
postOrder(node->right, result);
result.push_back(node->val);
}
};
2.迭代遍历二叉树
- 遍历时应该注意对空节点的判断
- 迭代遍历注意中序和前后序不同
- 前序遍历:使用栈,中左右的顺序,因此遍历的时候先将根节点压入栈,然后while循环 弹出后将按照右左节点的顺序弹出
- 后续遍历:和前序遍历类似,前序遍历先弹出中节点,然后修改为先压左节点再压入右节点,这样遍历出来的节点顺序是中右左,而后续遍历时左右中,将修改后的前序遍历输出反转
- 中序遍历:使用遍历节点,从根节点开始一直向左访问,知道遇见空,弹出栈顶后,将右节点再压入栈中
// 前序遍历
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> st;
if(root != NULL) st.push(root);
else return result;
while(!st.empty()){
TreeNode* topNode = st.top();
st.pop();
result.push_back(topNode->val);
// 忘了判断节点是否为空
if(topNode->right != NULL) st.push(topNode->right);
if(topNode->left != NULL) st.push(topNode->left);
}
return result;
}
// 中序遍历
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> st;
if(root == NULL) return result;
TreeNode* cur = root;
while(cur!=NULL || !st.empty()){
if(cur!=NULL){
st.push(cur); // 左
cur = cur->left;
}else{
cur = st.top();
st.pop();
result.push_back(cur->val); // 中
cur = cur->right; // 右
}
}
return result;
}
// 后序遍历
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> st;
if(root==NULL) return result;
st.push(root);
while(!st.empty()){
TreeNode* topNode = st.top();
st.pop();
result.push_back(topNode->val);
if(topNode->left != NULL) st.push(topNode->left);
if(topNode->right != NULL) st.push(topNode->right);
}
reverse(result.begin(), result.end());
return result;
}
3. 统一迭代法
- 中序遍历:在每一个遍历到但是没有添加到结果集的中间节点后添加一个空元素
// 统一迭代法
vector<int> inorderTraversal(TreeNode* root){
vector<int> result;
stack<TreeNode*> st;
if(root == NULL) return result;
TreeNode* cur = root;
st.push(root);
while(!st.empty()){
cur = st.top();
if(cur != NULL){
st.pop();
if(cur->right) st.push(cur->right);
st.push(cur);
st.push(NULL); // 遍历的每个中间节点后都会添加一个空节点,
if(cur->right) st.push(cur->left);
}else{
st.pop();
cur = st.top(); // 中间节点
st.pop();
result.push_back(st->val);
}
}
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> st;
if(root==NULL) return result;
TreeNode* cur = root;
st.push(root);
while(!st.empty()){
cur = st.top();
if(cur != NULL){
st.pop();
if(cur->right) st.push(cur->right);
if(cur->left) st.push(cur->left);
st.push(cur);
st.push(NULL);
}else{
st.pop();
cur = st.top();
st.pop();
result.push_back(cur->val);
}
}
return result;
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> st;
if(root==NULL) return result;
st.push(root);
TreeNode* cur = root;
while(!st.empty()){
cur = st.top();
if(cur != NULL){
st.push(NULL);
if(cur->right) st.push(cur->right);
if(cur->left) st.push(cur->left);
}else{
st.pop();
cur = st.top();
result.push_back(cur->val);
st.pop();
}
}
return result;
}