二叉树专题总结
一、公式总结
1. 二叉树
- 非空二叉树的叶子节点等于度为2的节点数+1,即 n 0 = n 2 + 1 n_{0}=n_{2}+1 n0=n2+1
- 非空二叉树的第n层至多有 2 n − 1 2^{n-1} 2n−1个节点
- 高度为k的二叉树至多有 2 k − 1 2^{k}-1 2k−1个节点
- 具有N个节点的二叉树的高度是 l o g 2 ⌊ ( N + 1 ) ⌋ log_{2}\left \lfloor \left ( N+1 \right ) \right \rfloor log2⌊(N+1)⌋层或者是 l o g 2 ⌊ ( N ) ⌋ + 1 log_{2}\left \lfloor \left ( N \right ) \right \rfloor+1 log2⌊(N)⌋+1层
- 非空二叉树节点的性质: N = n 0 + n 1 + n 2 N=n_{0}+n_{1}+n_{2} N=n0+n1+n2
2. 满二叉树
满二叉树就是每一层的节点都放满了
- 叶子只能出现在最下一层。出现在其它层就不可能达成平衡。
- 非叶子结点的度一定是2。
- 在同样深度的二叉树中,满二叉树的结点个数最多,叶子数最多
3. 完全二叉树
完全二叉树除了最后一层节点数都满,且最后一层的节点为左排列。
- 叶子结点只能出现在最下层和次下层。
- 最下层的叶子结点集中在树的左部。
- 倒数第二层若存在叶子结点,一定在右部连续位置。
- 如果结点度为1,则该结点只有左孩子,即没有右子树。
- 同样结点数目的二叉树,完全二叉树深度最小。
- 注:满二叉树一定是完全二叉树,但反过来不一定成立。
二、二叉树的遍历
1. 前序遍历
前序遍历的顺序是,中左右,即按照树的结构,先遍历二叉树的根节点,然后依次遍历左子树和右子树
结果为:ABDECF
代码
//递归
void traversal(TreeNode* cur,vector<int>& res)
{
if(cur==NULL) return;
res.push_back(cur->val);
traversal(root->left,res);
traversal(root->right,res);
}
//统一迭代法
vector<int>preTraversal(TreeNode* root)
{
vector<int>result;
stack<TreeNide*>st;
if(root==NULL) return result;
st.push(root->val);
while(!st.empty())
{
TreeNode* 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;
}
2. 中序遍历
中序遍历的顺序是,左中右,即按照树的结构,先遍历二叉树的左子树,然后遍历根节点,最后遍历右子树
结果为:DBEAFC
代码:
//递归
void traversal(TreeNode* root,vector<int> result)
{
if(root==NULL) return;
if(root->left) traversal(root->left,result);
result.push_back(root->val);
if(root->right) traversal(root->right,result);
}
//统一迭代法
vector<int> inTraversal(TreeNode* root)
{
vector<int> result;
stack<TreeNide*>st;
if(root!=NULL) st.push(root);
while(!st.empty())
{
TreeNode* cur=st.top();
if(cur!=NULL)
{
st.pop();
if(cur->right) st.push(cur->right);
st.push(cur);
st.push(NULL);
if(cur->left) st.push(cur->left);
}
else{
st.pop();
cur=st.top();
result.push_back(cur->val);
st.pop();
}
}
return result;
}
3. 后序遍历
后序遍历的顺序是,左右中,即按照树的结构,先遍历二叉树的左子树,然后依次遍历右子树,最后遍历根节点
结果为:DEBFCA
void traversal(TreeNode* root,vector<int>& result)
{
if(root==NULL) return ;
if(root->left) traversal(root->left,result);
if(root->right) traversal(root->right,result);
result.push_back(root->val);
}
vector<int> inTraversal(TreeNode* root)
{
vector<int> result;
stack<TreeNide*>st;
if(root!=NULL) st.push(root);
while(!st.empty())
{
TreeNode* cur=st.top();
if(cur!=NULL)
{
st.pop();
st.push(cur);
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;
}
4. 层序遍历
层序遍历的就是按照一层一层的往下遍历即可。
遍历结果:ABCDEF
代码
//借助队列
vector<vector<int>> levelOrder(TreeNode* root)
{
vector<vector<int>> result;
queue<TreeNode*> que;
if(root!=NULL) que.push(root);
while(!que.empty())
{
int size=que.size();
vector<int> res;
for(int i=0;i<size;i++)
{
TreeNode* node=que.front();
que.pop();
res.push_back(node->val);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
result.push_back(res);
}
return result;
}
三、二叉搜索树
二叉搜索树(BST,Binary Search Tree),也称二叉排序树或二叉查找树。
二叉搜索树:一棵二叉树,可以为空;如果不为空,满足以下性质:
- 非空左子树的所有键值小于其根结点的键值。
- 非空右子树的所有键值大于其根结点的键值。
- 左、右子树都是二叉搜索树
其最重要重要的就是,二叉搜索树的中序遍历结果是一个有序数组
1. 二叉搜索树的搜索
注意是二叉搜索树的搜索,不是遍历。
对于二叉搜索树的搜索,我们要注意使用二叉树的特性,即左孩子的值小于根节点的值小于右孩子的值。借助这一点,我们在搜索二叉树时,便可以很方便的根据值的大小,直接搜索了,而不用依次遍历每一个节点。
力扣题目号为:700,28
2. 二叉搜索树的遍历
二叉搜索树的遍历一定要善于使用其有序性这个特点,使用中序遍历的方法,记住在递归中是左中右的顺序。
很多题都是基于二叉树的遍历上的。力扣题号为:98、530、501等
3. 二叉搜索树的删除修剪
对于二叉搜索树的节点删除,对于我本人来说,第一次见到的时候也是有点恐慌,因为,想到对于树的重建,需要对二叉搜索树做较为复杂的删除和添加操作。然而实际上,对于二叉搜索树的删除节点操作并不需要那么复杂,我们只需要在返回节点的时候,返回有用的节点就行,该节点将会自动的连接到相应的地方即可,对于需要删除的节点,并不需要删除,而是直接跳过即可。
力扣题号:450、669