代码随想录训练营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& 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& 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;
    }
};

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

迭代遍历(需理解)

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

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

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

实现后序遍历(左右中)

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

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

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

迭代很难,还要再仔细看

你可能感兴趣的:(算法,数据结构,leetcode)