满二叉树、完全二叉树、二叉搜索树
满二叉树:只有度为0或2的结点,并且度为0的结点在同一层上
完全二叉树:除了最底层结点可能没填满,其他各层都填满了,并且最底层的结点都集中在最左边。
以上是没数值的树
二叉搜索树:是有数值的树,而且保持有序
二叉树的存储方式
链式存储、顺序存储(数组)
顺序存储:对于下标为i的节点,左孩子是i2+1,右孩子是i2+2
链式存储:
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
二叉树的遍历、插入、反转
class Solution {
public:
void dfs(TreeNode *p) {
if(p->left) dfs(p->left);
cout<<p->val<<' ';
if(p->right) dfs(p->right);
}
TreeNode* add(TreeNode *p, int value) {
if(p == nullptr) {
return new TreeNode(value);
}else if(p->val > value) {
p->left = add(p->left, value);
return p;
}else if(p->val < value) {
p->right = add(p->right, value);
return p;
}
}
TreeNode* invertTree(TreeNode* root) {
if(root == nullptr) return root;
swap(root->left, root->right);
root->left = invertTree(root->left);
root->right = invertTree(root->right);
return root;
}
};
二叉树的顺序存储
// 二叉树的数组初始化
TreeNode* init(vector<int> v) {
if(v.size()==0) return nullptr;
TreeNode* root = new TreeNode(v[0]);
queue<TreeNode*> q;
q.push(root);
for(int i=1;i<v.size();i++) {
TreeNode* tmp = q.front();q.pop();
if(v[i]!=-1) {
tmp->left = new TreeNode(v[i]);
q.push(tmp->left);
}
if(v[++i]!=-1) {
tmp->right = new TreeNode(v[i]);
q.push(tmp->right);
}
}
return root;
}
完全二叉树深度的利用
https://leetcode-cn.com/problems/count-complete-tree-nodes/
log*log时间复杂度计算完全二叉树节点个数
pair<int,int> countDepth(TreeNode* p) {
int l=0, r=0;
while(p) {
l++;
p=p->left;
}
while(p) {
r++;
p=p->right;
}
return make_pair(l,r);
}
int countNodes(TreeNode* root) {
if(root==nullptr) return 0;
int res = 1;
auto left = countDepth(root->left);
if(left.first == left.second) {
res+=(1<<left.first)-1;
}else {
res+=countNodes(root->left);
}
auto right = countDepth(root->right);
if(right.first == right.second) {
res+=(1<<right.first)-1;
}else {
res+=countNodes(root->right);
}
return res;
}
平衡二叉树
最近公共祖先
方法一:求LCA(x,y)只需要从x向上遍历到根节点并且把每个节点标记,然后从y向上遍历知道需要标记过的节点
方法二:fx代表x节点的后代中是否有x或y,那么lca就是满足左右子树都包含x或y,或者本身是x或y且左子树或右子树包含x或y
方法三:如果是有序二叉树,还可以利用节点在区间内来判断节点是否在子树内