代码随想录训练营Day14二叉树|理论基础|递归遍历|迭代遍历|统一迭代

理论基础

1、 二叉树的种类
满二叉树,结点数量:2^k-1
完全二叉树,除了底层,其他层是满二叉树,底层从左到右结点连续(堆,就是完全二叉树)
二叉搜索树(有序树),左子树小于中间结点,右子树大于中间结点
平衡二叉搜索树(有序树),左子树和右子树深度差不超过1(map,set,multimap,multiset底层实现,因此元素有序)

2、 二叉树的存储方式
链式存储(指针),每个结点有节点元素、两个指针,分别指向左右子节点(常用);
顺序存储(数组,有下标和元素),下表ix2+1为左孩子,ix2+2为右孩子。

3、 二叉树遍历
深度优先搜索(递归实现,如前中后序遍历,也可以用迭代),一个方向走到黑
​ 前序遍历:中左右;中序遍历:左中右;后序遍历:左右中
广度优先搜索(迭代层序遍历,栈实现)

4、 二叉树的定义(非核心代码模式下如何自己定义二叉树结点)
struct TreeNode{
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x): val(x),left(NULL), right(NULL){}
};

递归遍历

如何写递归(以前序遍历为例)

  • 确定递归函数的参数返回值
    传入指针和存放节点数值的vector void traversal(TreeNode* cur,vector<int>& vec)
  • 确定终止条件
    遍历的当前节点的空时结束 if(cur == NULL) return;
  • 确定单层递归的逻辑
    vec.push_back(cur->val);    //中
    traversal(cur->left, vec);  //左
    traversal(cur->right, vec); //右
    
  • 完整代码:
class Solution{
public:
    void traversal(TreeNode* cur, vector<int>& vec){
        if(cur == NULL) return;
        
        vec.push_back(cur->val);
        traversal(cur->left, vec);
        traversal(cur->right,vec);
    }
    
    vector<int> preorderTraversal(TreeNode* root){
        vector<int> result;
        traversal(root, result);
        return result;
    }
};

144.前序遍历 &145.后序遍历&94.中序遍历

迭代遍历(需理解)

  • 递归的实现:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回时,从栈顶弹出上一次递归的各项参数(这就是为什么递归可以返回上一层位置的原因)

迭代法实现前序遍历(中左右)

  • 第一层,中间节点入栈,并访问!!!所以该方法下必须先读中间节点
  • 第二层,右左节点顺序入栈(为了出栈时顺序为左右)
  • 第三层,在第二层的某个节点出栈时,立刻遍历第三层,以此类推

实现后序遍历(左右中)

  • 用和前序遍历同样的方法实现“中右左”,然后颠倒顺序实现“左右中”

实现中序遍历(左中右,难)

  • 和上面的写法不同,因为遍历顺序和处理顺序不同
  • 循环中止条件cur指针为空,stack栈也为空时
  • 先从左遍历到底,然后返回的同时弹出,并访问右边
  • 细品,以左为主,以中、右为辅,当遍历到右节点时,把他当做中间节点来处理
class Solution{
public:
    vector<int> inorderTraversal(TreeNode* root){
        vector<int> result;
        if(root == nullptr) return result;
        stack<TreeNode*> st;
        
        TreeNode* cur = root;

        while(cur!=nullptr || !st.empty()){
            if(cur){
                st.push(cur);
                cur = cur->left;
            }else{
                cur = st.top();
                result.push_back(cur->val); //中
                st.pop();
                cur = cur->right;                 
            }
        }
        return result;
    }
};

统一迭代

  • 标记法,将要处理的节
  • 点也放入栈中,但是后面紧跟一个空指针作为标记
  • 前中后序遍历间仅相隔两行代码
  • 后面没有接nullptr的节点,先出栈,再按顺序入栈,入栈时,处理节点后加nullptr
  • 中序遍历完整代码:
class Solution{
public:
    vector<int> inorderTraversal(TreeNode* root){
        vector<int> result;
        stack<TreeNode*> st;
        if(root == nullptr) return result;
        st.push(root);        

        while(!st.empty()){
            TreeNode* cur = st.top();
            if(cur != nullptr){
            	//前中后序的区别在于这里的顺序
                st.pop();
                if(cur->right)st.push(cur->right);
                st.push(cur);
                st.push(nullptr);
                if(cur->left)st.push(cur->left);
            }else{
                st.pop();  //nullptr;
                cur = st.top();
                st.pop();
                result.push_back(cur->val);
            }
        }
        return result;
    }
};

迭代很难,还要再仔细看

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值