对于二叉树的题目的相关理解

一棵完全二叉树,结点总数为1001,求它的叶子结点总数,度为2的结点总数,有多少个结点只有非空左子树,有多少个结点只有非空右子树?

总结以下两种理解方式:

1.完全二叉树的最后一个结点的编号是n,则它的父结点的编号为[n/2],则叶子结点个数为n-[n/2]。 结点数为奇数,所以度为1的结点有0个;所以非空左子树为0;非空右子树为0;

完全二叉树的最后一个结点的编号一定是1001,则它的父结点的编号为1001/2=500,则叶子结点个数为1001-500=501.非空左子树为0;非空右子树为0;

2.结点数为奇数,所以度为1的结点有0个,度为2的节点数=度为0的节点数-1,所以2*度为0的节点数-1 = 1001,所以度为0的节点数为501

n0 = n2 + 1,代入n0 + n1 + n2 = 1001得到2n2 + 1+ n1 = 1001, n1只能是0或者1,为满足2n2 + 1 + n1 = 1001,必须n1 =0,因此n2 = 500,所以n0 = 501,即叶子个数是501个

根据后序和中序遍历结果还原二叉树

思路: 1)后序遍历的最后一位即是二叉树的根节点。 2)然后再中序遍历找到根结点,根节点左边的所有序列便是左子树的中序遍历结果,右边的所有序列便是右子树中序遍历结果。 3)在后序遍历中找到对应的左子树,右子树。 4)在左右子树的先序和中序结果中继续重复1 , 2 ,3步骤,便可还原二叉树。 如下图:

根据先序中序还原二叉树

先序遍历:根 —> 左 —> 右

中序遍历:左 —> 根 —> 右

后序遍历:左 —> 右 —>根

算法思想: 根据先序遍历的特点,第一个遍历的结点就是根结点,我们找到根结点

根据中序遍历的特点,我们知道此根结点左边的序列为左子树,根结点右侧的序列为右子树

根据原始的先序和中序遍历结果,得到左右子树的先序和中序遍历结果,递归还原二叉树

根据遍历结果构造子树的遍历结果: 后序遍历:[ [ 左子树后序遍历结果 ],[ 右子树后序遍历结果 ],根节点] 中序遍历:[[ 左子树中序遍历结果 ],根节点,[ 右子树中序遍历结果 ]]举例:

preorder = [3,9,20,15,7] inorder = [9,3,15,20,7]

首先我们根据preorder知道结点3为整个树的根结点,然后根据inorder序列知道3左侧的序列[9]为左子树,右侧的序列[15,20,7]为右子树,就像这样

接下来我们构造左右子树的先序和中序遍历序列:

left_preorder = [9] right_preorder = [20,15,7]

left_inorder = [9] right_inorder = [15,20,7]

接下来就是递归的过程了。按照同样的步骤,根据preorder序列的第一个元素得到根结点,根据得到的这个根结点以及inorder得到左右子树,就像这样:2

 #include<iostream>
 #include<vector>
 #include<algorithm>
 ​
 using namespace std;
 ​
 struct Node{
     char data;
     Node* left;
     Node* right;
     Node(char data){
         this->data = data;
         this->left = nullptr;
         this->right = nullptr;
     }
 };
 ​
 vector<char> getCharArray(string str){
     vector<char> res;
     for(char c : str){
         res.push_back(c);
     }
     return res;
 }
 ​
 Node* getTree(vector<char>& preOrder, vector<char>& inOrder){
     if(preOrder.empty()){
         return nullptr;
     }
     Node* root = new Node(preOrder[0]);//构造根结点
     vector<char>::iterator mid = find(inOrder.begin(), inOrder.end(), preOrder[0]);
     int left_nodes = mid - inOrder.begin();
     vector<char> left_inOrder(inOrder.begin(), mid);
     vector<char> right_inOrder(mid+1, inOrder.end());
     vector<char> left_preOrder(preOrder.begin()+1, preOrder.begin()+1+left_nodes);
     vector<char> right_preOrder(preOrder.begin()+1+left_nodes, preOrder.end());
     root->left = getTree(left_preOrder, left_inOrder);
     root->right = getTree(right_preOrder, right_inOrder);
     return root;
 }
 ​
 void postOrder(Node* root){
     if(root == nullptr){
         return ;
     }
     postOrder(root->left);
     postOrder(root->right);
     cout<<root->data;
 }
 ​
 int main(){
     string pre_str;
     string in_str;
     while(cin >> pre_str >> in_str){
         vector<char> preOrder = getCharArray(pre_str);
         vector<char> inOrder = getCharArray(in_str);
         Node* root = getTree(preOrder, inOrder);
         postOrder(root);
         cout<<endl;
     }
     return 0;
 }
 ​
 ​

关于层次序列和中序序列还原二叉树的方式

就是使用层次序列找到根节点,在通过中序序列找到左右子树的分布,再通过左右子树和层次序列,再找到根节点,再通过同样的方式来操作。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ac果

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值