又论二叉树2.0

本文详细介绍了二叉树的链式结构及其功能,包括节点的创建、链接、遍历(前中后序)、节点计数、叶子节点计数、第k层节点数、查找特定值的节点、层序遍历、完全二叉树的判断以及二叉树的销毁。此外,还讨论了几个在线判题平台(OJ)上的二叉树题目,如单值二叉树、最大深度、翻转、相同树、对称树、平衡二叉树、子树判断和二叉树遍历等。
摘要由CSDN通过智能技术生成

---------------------这片博客主要是总结二叉树部分的练习

主要有另个部分,一是二叉树链式结构、极其功能。二是相关而查实OJ。

-------------前言

(1)二叉树链式结构极其功能:

①链表的构建:

typedef int TreeDataType;

typedef struct TreeNode{
	TreeDataType * data;
	struct TreeNode* left;
	struct TreeNode* right;
}TNode;                            

TNode* MyCreateTreeNode(char tmp);      //初始化二叉树~

 

九个节点的开辟。

②链接:

         

为了检验我们是否链接成功,我们需要去遍历一遍二叉树.

③前中后序遍历:

 

前序遍历递归图: 

 

中序、后序代码依旧变更不多,也就不再多画图>

④二叉树节点个数:

求二叉树节点的个数,需要去遍历一遍二叉树,那么选什么遍历容易些呢? 答案是后序。

求二叉树节点的个数有三种方法,其中很第一种和第二种的思想差多,就是环一种写法。最后一种就是传址变量++。 

在求完二叉树节点个数,也不能忘了 也可以求叶子节点个数

 ⑤叶子节点个数:

什么是叶子呢? 度为0 的节点,就叫做叶子节点。所以在求叶子节点的是时候就有思路了。

没有叶子就返回0,有叶子就返回1。总共有多少,就把左右子树相加。

⑥第k层 节点个数问题:

最后结果:

 ⑦ 二叉树寻找值为x 的节点:

 

⑧需借用队列的 层序遍历:

层序遍历 也是 二叉树遍历的一种,但它较为复杂。

层序遍历的思想很简单:

没层 从左到右依次遍历。但需要借助队列实现。

注:入一个数据 剔除一个数据 并保留下一个数据方便入。

即可以,达到层序遍历的效果。 

 倒入数据开始前,需要值得注意的是>_

 

 

⑨判断是否是完全二叉树:

要判断二叉树,是否是完全二叉树,就需要写下每层的层序。因此,层序遍历能帮助我们去判断二叉树的形状。

与层序遍历不同的是,需要把NULL 也放入队列,如果遇到NULL 就退出。

所以,在遇到第一个NULL 后就去寻找 队列剩下元素 是否含有节点>_

 

很明显我们构建的树并不是完全二叉树。 

 

如果我们在C的右子树 添加一个节点,并把G、H分别链接到D 的右边、E的左边。

⑩二叉树的销毁:

因为每个节点都是malloc开辟的。所以在销毁的时候,需要free掉每一个节点。

为了方便找寻下一个节点。所以采用后序遍历,一一free掉。

vesion1:

void BinaryTreeDestory(TNode* root)
{
	if (root == NULL)
		return;
	BinaryTreeDestory(root->left);
	BinaryTreeDestory(root->right);
	free(root);
}

手动置空

 vesion2:

    通过传二级指针进去置空


//通过里面改外面
void BinaryTreeDestory2(TNode** proot)
{
	if ((*proot) == NULL)
		return;
	//取地址不要忘了~!
	BinaryTreeDestory2(&(*proot)->left);
	BinaryTreeDestory2(&(*proot)->right);
	free(*proot);
	*proot = NULL;
}

也就成了完全二叉树了~ 

 上面也就简单谈了二叉树链式结构的一些功能。到此为止……

(2)二叉树的OJ习题

OJ习题列表:

1.单值二叉树https://leetcode.cn/problems/univalued-binary-tree/2.二叉树的最大深度https://leetcode.cn/problems/maximum-depth-of-binary-tree/3.翻转二叉树https://leetcode.cn/problems/invert-binary-tree/4.相同的树https://leetcode.cn/problems/same-tree/5.对称二叉树https://leetcode.cn/problems/symmetric-tree/

6.平衡二叉树https://leetcode.cn/problems/subtree-of-another-tree/7.另一棵树的子树https://leetcode.cn/problems/subtree-of-another-tree/8.二叉树遍历https://www.nowcoder.com/practice/4b91205483694f449f94c179883c1fef?tpId=60&&tqId=29483&rp=1&ru=/activity/oj&qru=/ta/tsing-kaoyan/question-ranking如果读者已经对上面的题了如指掌,也就不必再往下翻,见愚之见

OJ习题回顾:

1.单值二叉树:

bool isUnivalTree(struct TreeNode* root){
   if(root == NULL)
      return true;

  if(root->left&&root->left->val!=root->val)
      return false;
    if(root->right&&root->right->val!=root->val)
      return false;

  return isUnivalTree(root->left)
       && isUnivalTree(root->right);
}

 2.二叉树的最大深度

图示清晰地解释了,二叉树深度的遍历是后序。 

左右子树递归回来,那边高度高,就加哪边。

int maxDepth(struct TreeNode* root){
    if(root == NULL)
       return 0;
    int leftDepth=maxDepth(root->left);
    int rightDepth=maxDepth(root->right);

    return leftDepth>rightDepth? leftDepth+1:rightDepth+1;
}

3.翻转二叉树:


struct TreeNode* invertTree(struct TreeNode* root){
   if(root == NULL)
     return NULL;

   //开始交换
   struct TreeNode* tmp=root->right;
   root->right=root->left;
   root->left=tmp;
 
   //递归左
   invertTree(root->left);
   //递归右
   invertTree(root->right);

   return root;      
}

4.相同的树

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    //如果他们都为空树
   if(p==NULL && q==NULL)
      return true;

    //如果他们一个为空另外一个不为空
    if(p==NULL || q==NULL)
       return false;
    //节点数值不相等
    if(p->val!= q->val)
      return false; 

    //递归左右子树~
    return isSameTree(p->left,q->left)
           && isSameTree(p->right,q->right);
}

 5.对称二叉树:

bool isSameTree(struct TreeNode* left, struct TreeNode* right){
    //叶子空树对称
   if(left==NULL && right==NULL)
      return true;

    //如果他们一个为空另外一个不为空 结构不同
    if(left==NULL || right==NULL)
       return false;

    //节点数值不相等
    if(left->val != right->val)
      return false; 

    //递归左右子树~
    return isSameTree(left->left,right->right)
           && isSameTree(left->right,right->left);
}

bool isSymmetric(struct TreeNode* root){
     if(root == NULL)
       return true; 
    return isSameTree(root->left,root->right);
}

 6.平衡二叉树:

 首先分别求得左右子树的高度:

int maxDepth(struct TreeNode* root){
    if(root == NULL)
       return 0;
    int leftDepth=maxDepth(root->left);
    int rightDepth=maxDepth(root->right);

    return leftDepth>rightDepth? leftDepth+1:rightDepth+1;
}
bool isBalanced(struct TreeNode* root){
   if(root == NULL)
     return true;

   int leftmaxdepth=maxDepth(root->left);
   int rightmaxdepth=maxDepth(root->right);

   return  abs(leftmaxdepth-rightmaxdepth) <2
      &&isBalanced(root->left)  //多颗子树也要满足
      &&isBalanced(root->right);
}

此代码 的时间复杂度为最坏为O(N^2),因为有重复计算。

注:递归算法的时间复杂度=递归次数*每次递归函数的次数。


那如何提高效率呢?提升到O(N)?

把高度和是否为平衡树一起 进行判断

bool _isBalanced(struct TreeNode* root,int* ph)
{
    //最后一层为空 肯定是平衡的
   if(root ==NULL)
   {
    *ph=0;
     return true;
   }

   //左右子树的高度
   int lefthigh=0;
   //如果递归的子树 不是平衡树也直接返回
   if(_isBalanced(root->left,&lefthigh) == false)
       return false;

   int righthigh=0;
    if(_isBalanced(root->right,&righthigh) == false)  
      return false;

   *ph=fmax(righthigh,lefthigh)+1;
   //保证自己是平衡树
   return abs(righthigh-lefthigh)<2;

}   
bool isBalanced(struct TreeNode* root){
  int high=0;
  return _isBalanced(root,&high);
}

7.另一颗子树

bool _isSameTree(struct TreeNode* p, struct TreeNode* q){
    //如果他们都为空树
   if(p==NULL && q==NULL)
      return true;

    //如果他们一个为空另外一个不为空
    if(p==NULL || q==NULL)
       return false;
    //节点数值不相等
    if(p->val!= q->val)
      return false; 

    //递归左右子树~
    return _isSameTree(p->left,q->left)
           && _isSameTree(p->right,q->right);
}

bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){
    if(root == NULL)
       return false;
    //遍历S的树 和t比较
    //先比较自己
    if(_isSameTree(root,subRoot))  //---->每个节点去做根
        return true;
  
    //再去递归他的左右子树
     return isSubtree(root->left,subRoot)
        || isSubtree(root->right,subRoot);
}

 8.二叉树遍历

 还原的二叉树。

二叉树的链式:

typedef char TreeDataType;

typedef struct TreeNode
{
  TreeDataType data;
  struct TreeNode* left;
  struct TreeNode* right;
}TNode;

函数参数要将str 的内容放入到 二叉树里,用i 来访问str 的内容。因此要传地址,对唯一的i进行更新。

TNode* MycreatTreeNode(char* a,int* pi)
{
   if(a[*pi]=='#')
   {
       (*pi)++;
       return  NULL;
   }
   
  //构建根
  TNode* newnode=(TNode*)malloc(sizeof(TNode));  
  newnode->data=a[*pi]; 
    (*pi)++;
    
   //构建左右子树 
   newnode->left= MycreatTreeNode(a,pi);
   newnode->right= MycreatTreeNode(a,pi);
    
   return newnode;
}
void InorderTree(TNode* root)
{
// 中序打印
    if(root==NULL)
        return;
    InorderTree(root-left);
        printf("%c ",root->data);
     InorderTree(root-right);
}

 也就做完啦~

这是今天的内容,希望对诸位能有收获。

祝你好运~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值