文档讲解
二叉树 栈
二叉树结构
struct TreeNode
{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x):val(x),left(nullptr),right(nullptr){}
};
二叉树常用术语
- 根节点 root node:位于二叉树顶层的节点,没有父节点
- 叶节点 leaf node:没有子节点的节点,其两个指针均指向None。
- 边 edge:连接两个节点的线段,即节点引用(指针)。
- 节点所在层level:从顶到底递增,根节点所在层为1。
- 节点的度degree:节点的子节点的数量。在二叉树中,度的取值范围是0、1、2。
- 二叉树的高度height:从根节点到最远节点所经过的边的数量。
- 节点的深度depth:从根节点到该节点所经过的边的数量。
- 节点的高度height:从距离该节点最远的叶节点到该节点所经过的边的数量。
二叉树的类型
-
完美二叉树(满二叉树)
在满二叉树中,叶子节点的度为0,其余所有节点的度都为2;若树高度为h,节点总数为 2 h + 1 − 1 2^{h+1}-1 2h+1−1。
-
完全二叉树
与满二叉树的区分,只有底层的节点没有被填满,且其填满的顺序是从左到右填充。
-
完满二叉树
除了叶节点之外,其余所有节点都有两个子节点。
-
平衡二叉树
平衡二叉树中左子树和右子树的高度之差的绝对值不超过1。
-
二叉树的退化
二叉树的退化:当所有节点都偏向一侧时,二叉树退化为“链表”。
二叉树的遍历
递归遍历:
1.前序遍历
144.二叉树的前序遍历
时间复杂度:O(n)
空间复杂度:O(n)
class Solution {
public:
void preorder(TreeNode* node,vector<int>& result)
{
if(node==nullptr) return;
result.push_back(node->val);
preorder(node->left,result);
preorder(node->right,result);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
preorder(root,result);
return result;
}
};
2.中序遍历
94.二叉树的中序遍历
时间复杂度:O(n)
空间复杂度:O(n)
class Solution {
public:
void inorder(TreeNode* node,vector<int>& result)
{
if(node==nullptr)return;
inorder(node->left,result);
result.push_back(node->val);
inorder(node->right,result);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
inorder(root,result);
return result;
}
};
3.后序遍历
145.二叉树的后序遍历
时间复杂度:O(n)
空间复杂度:O(n)
class Solution {
public:
void postorder(TreeNode* node,vector<int>& result)
{
if(node==nullptr)return;
postorder(node->left,result);
postorder(node->right,result);
result.push_back(node->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
postorder(root,result);
return result;
}
};
迭代法:
思路:首先我们使用了递归法来完成了三种遍历方法,因为递归的过程就是一个不断使用栈的过程,故我们可以使用栈这种数据结构来存
1.前序遍历
时间复杂度:O(n)
空间复杂度:O(n)
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> stk;
if(root==nullptr)return result;
stk.push(root);
while(!stk.empty())
{
TreeNode* node=stk.top();
stk.pop();
result.push_back(node->val);
if(node->right)stk.push(node->right);
if(node->left)stk.push(node->left);
}
return result;
}
};
2.中序遍历
时间复杂度:O(n)
空间复杂度:O(n)
思路:
可以从这个遍历过程看出,对于迭代法写中序遍历而言,每次都应该将这个子树走完。即其作为上一个树的左节点,但是其在下一层又是中间节点。故为什么每次给result添加数据都是中这一步, 每个节点都可以看成中,取决你在哪一层的问题!
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> stk;
TreeNode* cur=root;
while(cur!=nullptr||!stk.empty())
{
if(cur!=nullptr)
{
stk.push(cur);
cur=cur->left;//左
}
else//只有访问到左边的空节点才能进入这里,此时的top(),相当于是中这个位置
{
cur=stk.top();//中
stk.pop();
result.push_back(cur->val);
cur=cur->right;//右
}
}
return result;
}
};
3.后序遍历
时间复杂度:O(n)
空间复杂度:O(n)
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> stk;
if(root==nullptr)return result;
stk.push(root);
while(!stk.empty())
{
TreeNode* node=stk.top();
stk.pop();
result.push_back(node->val);
if(node->left)stk.push(node->left);
if(node->right)stk.push(node->right);
}
reverse(result.begin(),result.end());
return result;
}
};
二叉树的统一迭代法
时间复杂度:O(n)
空间复杂度:O(n)
整个过程:1.65null4;2.65null24null1;3.65null24null1null;后面就弹出过程了。
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> st;
if(root!=nullptr)st.push(root);
while(!st.empty())
{
TreeNode *node=st.top();
if(node!=nullptr)
{
st.pop();
if(node->right)st.push(node->right);
st.push(node);
st.push(NULL);
if(node->left)st.push(node->left);
}
else
{
st.pop();
node=st.top();
st.pop();
result.push_back(node->val);
}
}
return result;
}
};