6.2 具有特殊性质的二叉树

本文详细探讨了四种特殊的二叉树类型:对称二叉树、完全二叉树、平衡二叉树和二叉搜索树。通过递归和迭代法,分别阐述了它们的定义、性质以及如何判断和遍历这些树。对于每个类型的二叉树,都提供了相应的LeetCode题目作为实例,展示了具体的解题思路和代码实现。
摘要由CSDN通过智能技术生成


6.2.1 对称二叉树

1. 对称二叉树的定义:

如果一棵二叉树是镜像对称的,那么这棵二叉树就叫做对称二叉树。

结合例题:力扣-101.对称二叉树

2. 递归法:

class Solution {
public:
    //递归法:树的内侧与内侧比较,外侧与外侧比较
    bool traverals(TreeNode* left, TreeNode* right)
    {
      //情况一:左右不同时为空
      if(left == nullptr && right != nullptr) return false;
      else if(left != nullptr && right == nullptr) return false;
      //情况二:左右同时为空
      else if(left == nullptr && right == nullptr) return true;
      //注意这里不可以用:else if(left->val == right->val) return true;
      //因为:左右孩子的值相等,不能说明是对称二叉树,是必要不充分条件
      else if(left->val != right->val) return false;
      else
      {
          return traverals(left->left, right->right) && traverals(left->right, right->left);
      }
    }

    bool isSymmetric(TreeNode* root) {
    if(root == nullptr) return true;
    return traverals(root->left, root->right);
    }
};

3. 迭代法

a.队列实现:

class Solution {
public:
    //队列实现迭代法
    bool isSymmetric(TreeNode* root) {
    if(root == nullptr) return true;
    queue<TreeNode*> que;
    que.push(root->right);
    que.push(root->left);
    while(!que.empty())
    {
        TreeNode* leftNode = que.front();
        que.pop();
        TreeNode* rightNode = que.front();
        que.pop();
        if( !leftNode && !rightNode) //如果左右都是空的,那就说明是对称的
        {
            continue;
        }
        if(!leftNode || !rightNode || (leftNode->val != rightNode->val)) //只要有且只有一个不是空的或者同侧值不相等,那就直接返回错误。
        {
            return false;
        }
        que.push(leftNode->left);
        que.push(rightNode->right); //把外侧结点压进去
        que.push(leftNode->right);
        que.push(rightNode->left); // 把内侧结点压进去
    }
    return true;
    }
};

b. 栈实现

其实,此题中的栈实现和队列实现是一回事,所用的思路都是深度优先遍历

class Solution {
public:
    //队列实现迭代法
    bool isSymmetric(TreeNode* root) {
    if(root == nullptr) return true;
    stack<TreeNode*> stk;
    stk.push(root->right);
    stk.push(root->left);
    while(!stk.empty())
    {
        TreeNode* leftNode = stk.top();
        stk.pop();
        TreeNode* rightNode = stk.top();
        stk.pop();
        if( !leftNode && !rightNode) //如果左右都是空的,那就说明是对称的
        {
            continue;
        }
        if(!leftNode || !rightNode || (leftNode->val != rightNode->val)) //只要有且只有一个不是空的或者同侧值不相等,那就直接返回错误。
        {
            return false;
        }
        stk.push(leftNode->left);
        stk.push(rightNode->right); //把外侧结点压进去
        stk.push(leftNode->right);
        stk.push(rightNode->left); // 把内侧结点压进去
    }
    return true;
    }
};

6.2.2 完全二叉树

1. 完全二叉树的定义:

在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^(h-1)个节点。
结合例题 : 力扣-222.完全二叉树的结点个数

2. 递归法:

class Solution {
public:
    //递归法
    int getNodes(TreeNode* root, int& count)
    {
        //递归的终止条件:
        if(root == nullptr) return 0;

        //单层递归:(前序遍历)
        count++;
        getNodes(root->left, count);
        getNodes(root->right, count);
        return count;
    }

    int countNodes(TreeNode* root) {
    int count = 0;
    return getNodes(root, count); 
    }
};

3. 迭代法:

class Solution {
public:
    //迭代法:中序遍历
    int countNodes(TreeNode* root) {
    if(root == nullptr) return 0;
    stack<TreeNode*> stk;
    stk.push(root);
    int count = 0;
    while(!stk.empty())
    {
       TreeNode * cur = stk.top();
       if(cur != nullptr)
       {
           stk.pop();
           if(cur->right) stk.push(cur->right);
           stk.push(cur);
           stk.push(nullptr); // 这里加入空标记,作用是标记根节点的位置
           if(cur->left) stk.push(cur->left);
       }else{
           stk.pop();
           cur = stk.top();
           stk.pop();
           count++;
       }
    }
    return count;
    }
};

4. 层序遍历法

class Solution {
public:
    //层序遍历法:
    int countNodes(TreeNode* root) {
    if(root == nullptr) return 0;
    queue<TreeNode*> que;
    que.push(root);
    int count = 0; // 计算结点数
    while(!que.empty())
    {
        int size = que.size();
        for(int i = 0; i<size; i++ )
        {
         TreeNode* cur = que.front();
         count++; //每弹出一个结点,就计数+1;
         que.pop();
         if(cur->left) que.push(cur->left);
         if(cur->right) que.push(cur->right);
        }
    }
    return count;
    }
};

6.2.3 平衡二叉树

1. 平衡二叉树的定义:

一棵二叉树的每一个结点的左右左右子树的高度差的绝对值不超过1
结合例题:力扣 – 110.平衡二叉树

2. 递归法:

思路:比较高度,用的是后序遍历

class Solution {
public:
   int getHeight(TreeNode*root)
   {
       //递归终止条件
       if(root == nullptr) return 0;

       //确定单层递归逻辑
       int leftHeight = getHeight(root->left); //拿到左树的高度
       if(leftHeight == -1) return -1;
       
       int rightHeight = getHeight(root->right); //拿到右树的高度
       if(rightHeight == -1) return -1;
        
        //比较左右子树的高度:如果是大于1,那就返回-1,如果是小于1,就返回该树的高度
       return abs(leftHeight - rightHeight) > 1? -1: 1 + max(leftHeight, rightHeight);
   }

    bool isBalanced(TreeNode* root) {
    //如果高度差为-1,则该二叉树不是平衡二叉树;
    //如果不是-1, 则该二叉树不是平衡二叉树;
    return getHeight(root) >= 0;
    }
};

3. 迭代法:

class Solution {
public:
class Solution {
public:
    //迭代法:利用栈实现迭代法

    //该函数功能:求出以当前结点为根节点的高度,也就是最大深度, 求高度 -- 后序遍历
    int getHeight(TreeNode* cur)
    {
        stack<TreeNode*> stk;
        if(cur != nullptr) stk.push(cur);
        int depth = 0; //记录深度
        int result = 0; //记录深度,也就当前结点的高度
        while(! stk.empty())
        {
            TreeNode* node = stk.top();
            if(node != nullptr)
            {
               stk.push(nullptr); //加入空标记,作用是标记当前的根节点位置
               depth++;
               if(node->right) stk.push(node->right);
               if(node->left) stk.push(node->left);
            }
            else
            {
              stk.pop();
              node = stk.top();
              stk.pop();
              depth--;
            }
            result = result > depth? result : depth;
        }
        return result;
    }

    //这里再使用一个栈:目的是求出左右子树的高度差
    bool isBalanced(TreeNode* root) {
       if(root == nullptr) return true;
       stack<TreeNode*> stk;
       stk.push(root);
       while( !stk.empty() )
       {
           TreeNode* node = stk.top();
           stk.pop();
           if(abs(getHeight(node->left) - getHeight(node->right) ) > 1) return false;  //使用的是前序遍历:自上而下判断
           if(node->right) stk.push(node->right);
           if(node->left) stk.push(node->left);
       }
       return true;
    }
};

6.2.4 二叉搜索树

1. 二叉搜索树的定义:

如果一棵二叉树同时满足以下三个条件条件:
·结点左子树中所含节点的值 小于 当前节点的值
·结点右子树中所含节点的值 大于 当前节点的值
·左子树和右子树都是二叉搜索树
那么这棵二叉树就是二叉搜索树
结合例题:力扣 - 98.验证二叉搜索树

2. 递归法:

class Solution {
public:
    //递归 -- 中序遍历 -- 检查元素是否从小到大
    //定义一个比较数据的值
    long long maxVal = LONG_MIN;
    bool isValidBST(TreeNode* root) {
    if(root == nullptr) return true;
    
    bool isLeft = isValidBST(root->left); //左边
   
    if(maxVal < root->val) maxVal = root->val; //中间
    else return false;
    
    bool isRight  = isValidBST(root->right); //右边
    
    return isLeft && isRight;
    }
};

3. 迭代法:

class Solution {
public:
    bool isValidBST(TreeNode* root) {
    if(root == nullptr) return true;
    stack<TreeNode*> stk;
    TreeNode* cur = root;
    TreeNode* per = nullptr;
    while(cur != nullptr || !stk.empty()) //因为后面要判断值,所以这个条件需要加上非空
    {
      if(cur != nullptr)
      {
        stk.push(cur); //当前节点进栈
        cur = cur->left; 
      }
      else
      {
        cur = stk.top();
        stk.pop();
        if(per && per->val >= cur->val)
        {
            return false;
        }
        per = cur;
        cur = cur->right;
      }
    }
    return true;
    }
};

参考资料:

《代码随想录》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Geminfit

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

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

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

打赏作者

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

抵扣说明:

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

余额充值