理论基础
二叉树的主要形式:满二叉树和完全二叉树
满二叉树的节点个数2的k次方-1(k是深度),满二叉树一定是完全二叉树
二叉搜索树:
- 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 它的左、右子树也分别为二叉排序树
平衡二叉搜索树:被称为AVL(Adelson-Velsky and Landis)树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
C++中map、set、multimap,multiset的底层实现都是平衡二叉搜索树,所以map、set的增删操作时间时间复杂度是logn
二叉树的存储方式
二叉树可以链式存储,也可以顺序存储。
链式存储:左指针,右指针
顺序存储:数组,如果父节点的数组下标是 i,那么它的左孩子就是 i * 2 + 1,右孩子就是 i * 2 + 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 travel(TreeNode*cur,vector<int>&vec){
if(cur==NULL)
return;
travel(cur->left,vec);
vec.push_back(cur->val);
travel(cur->right,vec);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int>result;
travel(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 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;
}
};
后序:
class Solution {
public:
void travel(TreeNode*cur,vector<int>&vec){
if(cur==NULL)
return;
travel(cur->left,vec);
travel(cur->right,vec);
vec.push_back(cur->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int>result;
travel(root,result);
return result;
}
};
迭代遍历
前序:
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();
st.pop();
result.push_back(node->val);
if(node->right)
st.push(node->right);
if(node->left)
st.push(node->left);
}
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:
vector<int> inorderTraversal(TreeNode* root) {
vector<int>result;
stack<TreeNode*>st;
TreeNode* cur=root;
while(cur!=NULL||!st.empty()){
if(cur!=NULL){
st.push(cur);
cur=cur->left;
}else{
cur=st.top();
st.pop();
result.push_back(cur->val);
cur=cur->right;
}
}
return result;
}
};
后序:先序遍历是中左右,后续遍历是左右中,那么我们只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转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:
vector<int> postorderTraversal(TreeNode* root) {
vector<int>result;
stack<TreeNode*>st;
if(root==NULL)
return result;
st.push(root);
while(!st.empty()){
TreeNode* node=st.top();
st.pop();
result.push_back(node->val);
if(node->left)
st.push(node->left);
if(node->right)
st.push(node->right);
}
reverse(result.begin(), result.end());
return result;
}
};
统一迭代
不增加自己负担了。
总结
二叉树的递归和迭代遍历要学会