二叉树性质
1.二叉树的第k层至多有(2^(k-1))个节点
2.k层的二叉树至多有(2^k-1)个节点,最少有k个节点
3.对任何一颗二叉树,如果其叶节点数为n0,树中度为2的节点个数为n2,那么可以得到n0 = n2+1.
//证明过程
总节点数满足 n = n0 + n1 + n2
除了根节点,每个节点对应一条边 e = 2n2 + n1 = n - 1
因此,有 2n2+ n1 =n0 + n1 + n2- 1
n2= n0 - 1 =>
n0= n2 + 1
空链域:2n0 + n1 = n0 + n2 + 1 + n1 = n + 1
4.具有n个结点的完全二叉树深度为(log2(n))+1。
高度为h的二叉树最多有2{h}–1个结点。反之,对于包含n个节点的二叉树的高度至少为log2(n+1)。
5.对具有n个结点的完全二叉树,如果按照从上至下和从左至右的顺序对二叉树的所有结点从1开始编号,则对于任意的序号为i的结点有如下性质。
如果i>1,那么序号为i的结点的双亲节点序号为i/2。
如果i=1,那么序号为i的节点为根节点,无双亲节点。
如果2i<=n,那么序号为i的结点的左孩子结点序号为2i;
如果2i>n,那么序号为i的结点无左孩子;
如果2i+1<=n,那么序号为i的结点右孩子序号为2i+1;
如果2i+1>n,那么序号为i的结点无右孩子。
1.普通二叉树
存在不是两个子节点的节点。
2.完全二叉树
除了最后一层,其他各层的节点个数都达到最大,最后一层左对齐。
3.满二叉树
所有非叶子节点的度都是2,也就是一个节点要么没有子节点,要么就要有两个子节点。
4.完美二叉树![在这里插入图片描述](https://img-blog.csdnimg.cn/20210427193754513.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNzk2Nzk1,size_16,color_FFFFFF,t_70)
完全二叉树加满二叉树。
5.二叉搜索树
所有
二叉树的遍历方式
前序遍历
排序CABEDGF
递归版本
void preorderTravesal(TreeNode * root,vector<int>&res)
{
if(!root)
return;
res.push_back(root->val);
if(root->left)
preorderTravesal(root->left,res);
if(root->right)
preorderTravesal(root->right,res);
}
非递归版本,使用栈进行存储
void preorderTravesal(TreeNode * root,vector<int>&res)
{
//如果为空树
if(!root)
return;
//栈
stack<TreeNode*> s;
//当前节点
TreeNode * node =root;
//判断是否存在
while(node||!s.empty())
{
//遍历到左子树
while(node)
{
s.push(node);
res.push_back(node->val);
node = node->left;
}
//栈顶节点
node = s.top();
//退出
s.pop();
//遍历右子树
node = node->right;
}
}
中序遍历
排序为ABCDEFG
递归版本
void midorderTravesal(TreeNode * root,vector<int>&res)
{
if(!root)
return;
if(root->left)
midorderTravesal(root->left,res);
res.push_back(root->val);
if(root->right)
midorderTravesal(root->right,res);
}
void midorderTravesal(TreeNode * root,vector<int>&res)
{
if(!root)
return;
stack<TreeNode*>q;
//记录当前节点
TreeNode * cur_node = root;
while(cur_node||!q.empty())
{
while(cur_node)
{
q.push(cur_node);
cur_node = cur_node->left;
}
cur_node = q.top();
q.pop();
res.push_back(cur_node->val);
cur_node = cur_node->right;
}
}
后序遍历
排序BACDFGE
递归版本
void postorderTravesal(TreeNode * root,vector<int>&res)
{
if(!root)
return;
if(root->left)
postorderTravesal(root->left,res);
if(root->right)
postorderTravesal(root->right,res);
res.push_back(root->val;
}
非递归版本
void postorderTraversal(TreeNode *root,vector<int>&res)
{
if(!root)
return;
stack<TreeNode*> s;
TreeNode *flag =NULL;
TreeNode *cur_node = root;
while(cur_node||!s.empty())
{
while(cur_node)
{
s.push(cur_node);
cur_node = cur_node->left;
}
cur_node = s.top();
if(!cur_node->right||flag == cur_node->right)
{
res.push_back(cur_node->val);
flag = cur_node;
s.pop();
cur_node = NULL;
}
else
{
cur_node = cur_node->right;
}
}
}
层序遍历
排序CAEBDGF
vector<vector<int>> levelorder(TreeNode * root)
{
vector<vector<int>> res;
if(root == NULL)
return;
queue<TreeNode*>q;
q.push(root);
TreeNode * cur_node;
while(!q.empty())
{
vector<int> tempv;
int sz = q.size();
while(sz--)
{
cur_node = q.front();
tempv.push_back(cur_node->val);
q.pop();
if(cur_node->left)
q.push(cur_node->left);
if(cur_node->right)
q.push(cur_node->right);
}
res.push_back(tempv);
}
}
找第k大/小
对于二叉搜索树来说,左子树所有值小于根节点,右子树所有值大于根节点。依据这个特性,我们可以简单得出结论:二叉搜索树上的第k小的节点即为中序遍历的第k个节点,第k大的节点
第k小的代码如下
遍历版
int count = 0;
TreeNode* KthNode(TreeNode* root, int k)
{
if(root){
TreeNode *cur_ans= KthNode(root->left, k);
if(cur_ans)
return cur_ans;
if(++count == k)
return root;
ret = KthNode(root->right,k);
if(cur_ans)
return cur_ans;
}
return nullptr;
}
非遍历版
//非遍历版
int count = 0; //计数器
TreeNode* cur_ans;
void dfs(TreeNode * p){
if(!p || count < 1)
return;
dfs(p->left);
if(count == 1)
cur_ans = p;
if(--count > 0)
dfs(p->right);
}
TreeNode* KthNode(TreeNode* root, int k)
{
cur_ans = nullptr;
count = k;
dfs(root);
return cur_ans;
}
保研机试题笔记,持续更新。