二叉树的理论基础
二叉树的分类
满二叉树
满二叉树是每一层结点都达到最大值的二叉树,满二叉树的结点数为2^k-1,k为深度。
完全二叉树
除了最层次外,其他层结点都达到了最大值,且最底层是从左至右连续的,
二叉搜素树
对二叉树的结点结构没有要求,对节点元素要求:节点之间一定要有顺序
- 若左子树不为空,则左子树上的节点值均小于根节点;
- 若右子树不为空,则右子树上的节点值均大于根节点;
- 左右子树均为二叉搜索树。
平衡二叉树
左子树和右子树的高度差不能超过1,在c++中,set和map底层实现就是平衡二叉树,而unodered set 和unodered map的底层是哈希表。
二叉树的递归遍历
思路:递归算法三要素
1.确定递归函数和参数的返回值
2.确定终止条件
- 确定单层递归的逻辑
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void binaryTree(TreeNode* cur , vector<int>& vec){//二叉树的前序遍历
if(cur == nullptr) return;//节点为空
vec.push_back(cur->val);//中
binaryTree(cur -> left , vec);//左
binaryTree(cur -> right , vec);//右
}
vector<int> preorderTraversal(TreeNode* root) {//返回前序遍历的节点值
vector<int> result;
binaryTree(root , result);
return result;
}
};
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void binaryTree(TreeNode* cur , vector<int>& vec){//二叉树的后序遍历
if(cur == nullptr) return;//节点为空
binaryTree(cur -> left , vec);//左
binaryTree(cur -> right , vec);//右
vec.push_back(cur->val);//中
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
binaryTree(root , result);
return result;
}
};
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void binaryTree(TreeNode* cur , vector<int>& vec){//二叉树的中序遍历
if(cur == nullptr) return;//节点为空
binaryTree(cur -> left , vec);//左
vec.push_back(cur->val);//中
binaryTree(cur -> right , vec);//右
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
binaryTree(root , result);
return result;
}
};
二叉树的迭代遍历
先序遍历
思路:
先将中间结点放入栈中,再放入右孩子,然后再放入左孩子,因为先放右孩子在出栈时才会有中左右的操作。
中序遍历
在实现中序遍历时和先序遍历是不一样的解题思路,在迭代过程中,主要有两个步骤:
1.处理:将元素放入result中
2.访问:遍历结点
分析一下为什么刚刚写的前序遍历的代码,不能和中序遍历通用呢,因为前序遍历的顺序是中左右,先访问的元素是中间节点,要处理的元素也是中间节点,所以刚刚才能写出相对简洁的代码,因为要访问的元素和要处理的元素顺序是一致的,都是中间节点。
那么再看看中序遍历,中序遍历是左中右,先访问的是二叉树顶部的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点(也就是在把节点的数值放进result数组中),这就造成了处理顺序和访问顺序是不一致的。
那么在使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。
二叉树的统一迭代法
先序遍历
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> st;
if (root != NULL) st.push(root);
while (!st.empty()) {
TreeNode* node = st.top();
if (node != NULL) {
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;
}
};
中序遍历
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> st;
if (root != NULL) 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;
}
};
后序遍历
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> st;
if (root != NULL) st.push(root);
while (!st.empty()) {
TreeNode* node = st.top();
if (node != NULL) {
st.pop();
st.push(node); // 中
st.push(NULL);
if (node->right) st.push(node->right); // 右
if (node->left) st.push(node->left); // 左
} else {
st.pop();
node = st.top();
st.pop();
result.push_back(node->val);
}
}
return result;
}
};