理论基础
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){}
};
递归遍历
如何写递归(以前序遍历为例)
- 确定递归函数的参数和返回值:
传入指针和存放节点数值的vectorvoid 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;
}
};