代码随想录算法训练营第14天
一、二叉树理论基础
二叉树的种类
- 满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。
- 完全二叉树:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。
- 二叉搜索树:二叉搜索树是一个有序树,若左子树不空,则对应的值小于根节点的值;若右子树不空,则对应的值大于根节点的值;左右子树均为排序树。
- 平衡二叉搜索树:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
二叉树的存储方式
- 链式存储:链式存储是通过指针把分布在各个地址的节点串联一起。
- 顺序存储:从上到下、从左到右按顺序通过数组索引储存,如果父节点的数组下标是 i,那么它的左孩子就是 i * 2 + 1,右孩子就是 i * 2 + 2。
二叉树的遍历方式
- 深度优先遍历
- 前序遍历(递归法,迭代法)
- 中序遍历(递归法,迭代法)
- 后序遍历(递归法,迭代法)
- 广度优先遍历
- 层次遍历(迭代法)
二叉树的定义
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) return;
vec.push_back(cur->val);
traversal(cur->left, vec);
traversal(cur->right, vec);
}
三、二叉树的迭代遍历
递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。迭代有点类似递归的底层栈实现。
前序遍历
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> result;
if(root == NULL) return result;
st.push(root);
while(!st.empty()){
TreeNode* node = st.top();
if(node != NULL){
st.pop();
if(node->right) st.push(node->right);
if(node->left) st.push(node->left);
st.push(node);
st.push(NULL);
}
else{
st.pop();
node = st.top();
st.pop();
result.push_back(node->val);
}
}
return result;
}
};