[数据结构]链式二叉树基础概念篇

Posted 一个正直的男孩

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[数据结构]链式二叉树基础概念篇相关的知识,希望对你有一定的参考价值。


看这篇博客之前我希望你具备基础的递归思想

//当N为6时
int Tmp(int n)

  if(n<2)
  
    return 1;
  
return Tmp(n-1)+Tmp(n-3);

如果你的答案是9,且对递归展开很清楚那么恭喜你下面文章就不会有阅读障碍


二叉树

链式二叉树的访问有一下4种情况,前中后序,而层序与他们有所不同,而二叉树的知识基本都是从这个中心点散发出去的,且下面的题都根据这着三种情况展开

1.1前序遍历

前序遍历是这样访问的:先是根 在是左子树 然后右子树

如上图所示二叉树的前序遍历是?:

1->2->4->6->7->3->5

代码:

 void Help(vector<int> &ch,TreeNode* root)
    
          if(root==nullptr)
          return;
          ch.push_back(root->val);//插入节点
          Help(ch,root->left);
          Help(ch,root->right);
    
    vector<int> preorderTraversal(TreeNode* root)
     
        vector<int>d1;
        Help(d1,root);
       return d1;
    

1.2中序遍历

左子树 根 右子树

如上图所示二叉树的前序遍历是?:

6->4->7->2->1->3->5

代码:

 void Help(vector<int> &ch,TreeNode* root)
    
          if(root==nullptr)
          return;
          Help(ch,root->left);
          ch.push_back(root->val);//插入节点
          Help(ch,root->right);
    

可以看出是先访问最左子树一直访问到不能访问的时候再去访问根在去访问右子树如此反复


1.3后序遍历

左子树 右子树 根

如上图所示二叉树的前序遍历是?:

6->7->4->2->5->3->1

 void Help(vector<int> &ch,TreeNode* root)
    
          if(root==nullptr)
          return;
          Help(ch,root->left);
          Help(ch,root->right);
          ch.push_back(root->val);//插入节点
    

你不难看出啥时候访问根就是啥遍历


1.4层序遍历

这个就非常好理解就是一个一个节点的从上往下访问

1->2->3->4->5->6->7

这个比较特殊他的实现一机不是基于递归而是队列

方法实现:每一个节点都有他对应的子节点,那么当该节点被访问出队列的时候他就把他的字节点带入队列中

如图所示:

void TreeSequence(TreeNode *node)

          //创建一个队列
          queue<TreeNode *>tmp;
          tmp.push(node);
          while(!tmp.empty())
          
                    if(tmp.front())//队头不为空
                    
                        cout<<tmp.front()->val<<' ';
                        //入数据
                        tmp.push(tmp.front()->left);
                        tmp.push(tmp.front()->right);
                    
              tmp.pop();//出数据
          


刷题


2.1:知道前/后 中序构造一颗二叉树(理论推导)

前序遍历:1,2,4,7,3,5,6,8

中序遍历:4,7,2,1,5,3,8,6

​ 做这类题一般先找根(这样就可以直接找到他的左右子树的个数)在确定左子树和右子树


下文中都以这颗二叉树为例子:


2.2 求一颗树的节点个数

     size_t TreeSize(TreeNode *root)//查看但前树的节点个数
      
          if(root==nullptr)
          
              return 0;
          

         return 1+TreeSize(root->left)+TreeSize(root->right);
      

单边的执行逻辑,另一边一也是同理,一直递归知道不能在递归然后返回当前节点他自自己右多个个节点,1就代表的当前节点自己


2.3 求一颗树叶子的节点

size_t LeafSize(TreeNode *root)

    if(root== nullptr)//他自己为空代表直接没有节点了
    
        return 0;
    
    if(root->left==root->right)//左节点和右节点在啥时候会相等呢?没错当然是没叶子的时候
    
        return 1;
    
       return LeafSize(root->left)+LeafSize(root->right);//返回左子树与右子树叶子节点的个数累加
      

这道题其实就是上一道题的变型,唯一不同的就是叶子节点他是没有儿子的那么就是说我们可以利用这个特性进行题解


2.4 求第k层节点个数

size_t TreeKSize(TreeNode *root,int k)
     
          if(root== nullptr)
          
              return 0;
          
          if(k==1)//这个和数组一样是从0开始的
          
              return 1;
          
          return TreeKSize(root->left,--k)+TreeKSize(root->right,--k);//一定要前置++因为后置++是这条语句结束后生效也就是说k不会变
      

利用既然你要的是k层的节点,你我就利用你作为条件,只要到这一层且我不为空那么那么这就是第k层的数据,如图所示,配合代码,在内心生成一个递归的样子,蓝线:递归,橘线:返回


2.5 求该树的层数

size_t TreeDeep(TreeNode *root)
      
          if(root==nullptr)
          return 0;

            int d1=1+TreeDeep(root->left);
            int d2=1+TreeDeep(root->right);
            //双路线,累加是在返回的时候

            return 1+d1>d2?d1:d2;//闭上最大值,且深底从1开始
      

这道题是上一道题的变形,求的不一样,这道题需要面临的是这样一个问题假如这个子树左右不是很对称怎么那怎么办,其实也好办值需要比出他们中最大节点的个数即可,如图所示:单边执行图 蓝色:递归 橙色:返回


2.6 检查俩课二叉树是否相等

如何判断俩个棵二叉树是否相等呢?你想如果是链表你如何判断相等,当然就是遍历楼,那二叉树也是如此一样,但是需要依靠四种遍历方法

bool isSameTree(TreeNode* p, TreeNode* q)
        
            if(p==nullptr&&q==nullptr)
            
                return true;
            
              if(p==nullptr||q==nullptr)//上面已经判断了俩个都是空的情况现在只剩一个为空的情况
              return false;
            if(p->val!=q->val)
            
                return false;
            
            return  isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);

        

该思路递归和求二叉树节点个数基本相同,唯一不同的就是你要控制俩棵二叉树,且多一个判断

假如p现已经为空,q还不为空,那么就是false,反之依然


2.7 单值二叉树

判断这颗树的节点是不是统一一个值,思路和2.6一样只需要遍遍整棵树就可以得出答案

bool IfSame(TreeNode* root,int value)
    
      if(root==nullptr)
            return true;
        if(root->val!=value)//不相等
        return false;

      return IfSame(root->left,value)&&IfSame(root->right,value);
    
    bool isUnivalTree(TreeNode* root) 
    
      return IfSame(root,root->val);
    

2.7 对称二叉树

上图就是一个标准的对称二叉树,本质就是从root节点树分为左子树与右子树,吧右子树翻一个面,就和照镜子一样,左右的值是相反的

代码:

 bool Symmetry(TreeNode*LT,TreeNode*RT)
    
        if(LT==nullptr&&RT==nullptr)//俩者都为空代表相同
        
            return true;
        
        if(LT==nullptr||RT==nullptr)
        
            return false;
        
        if(LT->val!=RT->val)
        
            return false;
        

        return Symmetry(LT->left,RT->right)&&Symmetry(LT->right,RT->left);
    
    bool isSymmetric(TreeNode* root)
    

       
       return Symmetry(root->left,root->right);
    

看代码你会发现这个思路好熟悉对没错,他也是2.6的一个变形,思路基本一样,唯一不一样的就是递归的节点罢了


2.8另一颗子树

判断subRoot是不是root中的一颗子树(即使subroot的结构root中有没有),这一块属于稍微进阶的玩法,我们现在不值要控制俩棵树的节点,还要控制俩个递归其实本质上没有区别依旧是遍历与判断

  1. 外层递归:遍历找root与subroot的根节点相同的节点
  2. 2.7对称二叉树一样可以说直接copy即可

代码:

bool Same(TreeNode* root, TreeNode* subRoot)//内层循环
    
        if(root==nullptr&&subRoot==nullptr)
        
            return true;
        
        if(root==nullptr||subRoot==nullptr)
        
            return false;
        
        if(root->val!=subRoot->val)
        
            return false;
        
        return Same(root->left,subRoot->left)&&Same(root->right,subRoot->right);//都为正才为真

    
    bool isSubtree(TreeNode* root, TreeNode* subRoot) //外层循环
      if(root==nullptr)
       
           return false;
       
       if(Same(root,subRoot))//直接控制比较root与subroot
        
           return true;;
        
       return isSubtree(root->left,subRoot)||isSubtree(root->right,subRoot);//左右子树中只要有一个为真即可
    
    

2.9 判断是不是完全二叉树

基于层序遍历,完全二叉树有什么性质,请你大声告诉我?

当然是每个节点都是连续的,且只有俩个子节点

yes,既然节点是连续的就是说等全部叶子节点都出完之后,这个队列中的数据都是 nullptr 那么他就是一颗完全二叉树

如图所示:

代码:

bool whole(TreeNode *node)//判断是不是一颗完全二叉树
    
        //创建一个队列
        queue<TreeNode *>tmp;
        tmp.push(node);
        while(!tmp.empty())
        
            if(tmp.front())
            
                cout<<tmp.front()->val<<' ';
                tmp.push(tmp.front()->left);
                tmp.push(tmp.front()->right);
            
            else
            
                break;
            
            tmp.pop();
        
        while(!tmp.empty())//判断剩余的节点是不是空
        
            if(tmp.front()!=nullptr)
            
                return false;
            
            tmp.pop();
        
        return true;
    
;




唠家常结尾

为啥你只画单边呀,emmmm,因为图纸大小不够了,且右一边看懂了另一边也是同样的逻辑,且全部展开也乱不是吗,在此声明绝对不是博主懒,着是一个初步认识,到后面STL中的会更加深入,博主已经写了几篇STL的博客感兴趣可以去瞅瞅看。

上述2.6~2.8的题目链接

以上是关于[数据结构]链式二叉树基础概念篇的主要内容,如果未能解决你的问题,请参考以下文章

Python数据结构系列☀️《树与二叉树-基础知识》——知识点讲解+代码实现☀️

二叉树,堆详解

数据结构C语言版——链式二叉树的基本操作实现

数据结构C语言版——链式二叉树的基本操作实现

数据结构与算法基础

数据结构----二叉树(未写完)