二叉树 —— OJ题目详解

1.二叉树的前序遍历

二叉树的前序遍历比较简单,但是在力扣上写这个接口需要注意几个点:

int* preorderTraversal(struct TreeNode* root, int* returnSize) {
    
}
  • preorderTraversal 的返回值是动态开辟的数组,里面存放的是前序遍历的顺序
  • int* returnSize 这个参数记录的是遍历到的数据个数,因为函数的返回值只能有一个,所以我们通它来记录,当用户需要数据个数时,直接查看该指针变量即可

 代码:


int TreeSize(struct TreeNode* root){
    if(root == NULL)
    return 0;
    return TreeSize(root->left) + TreeSize(root->right) + 1;
}

void _preOrder(struct TreeNode* root, int* a,int* i){
    if(root == NULL)
    return;

    a[*i] = root->val; //记录当前节点,到数组中
    (*i)++;            //数组下标+1

    _preOrder(root->left,a,i);  //接着遍历左子树
    _preOrder(root->right,a,i); //然后遍历右子树 

}

//returensize是记录数组的元素个数,我们要返回给用户的是遍历数的数组
int* preorderTraversal(struct TreeNode* root, int* returnSize) {

    *returnSize = TreeSize(root);//遍历树,得到数据个数

    int* a = (int*)malloc(sizeof(int) * (*returnSize));//动态开辟数组空间

    int i = 0;
    _preOrder(root ,a,&i);//前序遍历
    return a;

}

2.检查两棵树是否相同

思路: 

利用前序遍历,先比较当前节点是否相同,紧接着比较左子树与右子树

代码:

bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
    if(p == NULL && q == NULL) //如果pq都为NULL,返回真
        return true;

    if(p == NULL || q == NULL)  //代码到这里,只有2种可能,1.pq其中一个为NULL,2两个都不为NULL
                               //如果其中一个为NULL,说明另一个一定不是NULL,则pq不相等,不用
        return false;          //比较了,返回false


    if(p->val != q->val)  // 代码到这,说明pq都不为NULL,直接比较即可

        return false;    //比较qp相等没有用意义,要看它们不相等,可以直接出结果

    return isSameTree(q->left,p->left) //在比较左右子树,右子树
    && isSameTree(q->right,p->right);
}

3.对称二叉树

 思路:

观察示例一:一颗对称的二叉树,我的左子树根节点 == 你的右子树根节点、我的右子树根节点 == 你的左子树根节点。有一个地方不符合此规则,则此树不是对称二叉树

所以示例一是一颗对称二叉树,我们代码则使用递归的方法,先比较当前两棵树的根节点是否相同,在比较这两颗树的左右子树是否对称

代码:

bool _isSymmetric(struct TreeNode* q,struct TreeNode* p)
{
    //先比较当前两颗子树的根节点是都相同
    if(p == NULL && q == NULL) 
        return true;

    if(p == NULL || q == NULL)  //代码到这里,只有2种可能,1.pq其中一个为NULL,2两个都不为NULL
        return false;

    if(p->val != q->val)// 比较根节点是否相同
        return false;

    return _isSymmetric(q->left,p->right)   //q节点的左子树,与p节点的右子树比
    && _isSymmetric(q->right,p->left);     //q节点的右子树,与p节点的左子树比
}
bool isSymmetric(struct TreeNode* root) {
    return _isSymmetric(root->left,root->right);
}

4.另一棵树的子树

思路:

题目给出了root树与subRoot树,让我们看看sybRoot树是否是root树中的一个子树

 1.那么我们首先要做的是:如何找出root树的所有子树?

其实这个很简单,我们只需要遍历到root树的每一个节点就相当于找到了root树的所有子树,因为每一个节点都是某棵树的根节点,通过根节点自然得到了一节树

2.找到了所有子树之后我们要做的自然依次与subRoot树比较,看有没有相同的树了

我们前面已经写过检查两颗树是否相同,直接移植过来就可以

代码:

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(q->left,p->left)
    && isSameTree(q->right,p->right);
}

bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){

    if(root == NULL)//subRoot树上的节点数量范围是[1, 1000],所以当遍历到的子树为NULL时返回false
        return false;

     //当某一个子树的根节点与subRoot根节点相同时,开始比较两棵树是否相同
     //当两颗树相同则直接出结果,不用接着去找了,返回ture 
    if(root->val == subRoot->val &&
    isSameTree(root,subRoot))
        return true;

    //接着去遍历左子树与右子树,一边找到了就不用再继续找了,整体就是前序遍历的去遍历每一颗子树
    return isSubtree(root->left,subRoot) || isSubtree(root->right,subRoot);
}

5.二叉树的构建及遍历

利用,用户输入的数组先构建一颗二叉树,在进行中序遍历即可 

代码:

#include <stdio.h>
#include<stdlib.h>
typedef char BTDataType;

typedef struct BinaryTreeNode {
    BTDataType _data;
    struct BinaryTreeNode* _left;
    struct BinaryTreeNode* _right;
} BTNode;

BTNode* BuyNode(BTDataType x) {

    BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
    if (newnode == NULL) {
        perror("Buynode()::malloc()");
        return newnode;
    }

    newnode->_data = x;
    newnode->_left = NULL;
    newnode->_right = NULL;
    return newnode;
}

// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root) {
    if (root == NULL) {
        return;
    }

    BinaryTreeInOrder(root->_left);//左子树
    printf("%c ", root->_data);//根节点
    BinaryTreeInOrder(root->_right);
}

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a,int* pi) {

    //根,左子树,右子树

    if (a[(*pi)] == '#') {
        (*pi)++;
        return NULL;
    }

    BTNode* newnode = BuyNode(a[(*pi)++]);

    newnode->_left = BinaryTreeCreate(a,pi);
    newnode->_right  = BinaryTreeCreate(a,pi);

    return newnode;
}

int main() {
    char arr[101];
    scanf("%s",arr);
    int count = 0;
    BTNode* tree = BinaryTreeCreate(arr,&count);   //构建二叉树
    BinaryTreeInOrder(tree);                      //中序遍历二叉树
    return 0;
}

6.翻转二叉树

思路: 

依旧是使用递归,先翻转左子树,在翻转右子树。由于翻转后,左右子树的根节点没有动,最后在将根节点翻转即可完成当前树的翻转

代码:

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

    _invertTree(root->left);   //翻转左子树
    _invertTree(root->right);  //翻转右子树

    //在将自己左右子树的根节点交换,即可完成翻转
    struct TreeNode* temp = root->left;
    root->left = root->right;
    root->right = temp;
}
struct TreeNode* invertTree(struct TreeNode* root) {
    _invertTree(root);

    return root;
}

7.平衡二叉树

平衡二叉树: 每个节点的左右子树的深度相差不超过1

思路: 

遍历二叉树的每一个节点,算它们的高度差超过1吗,超过就不是平衡二叉树

代码:

int TreeHight(struct TreeNode* root)//求高度
{
    if(root == NULL)
    return 0;

    int left = TreeHight(root->left);
    int right = TreeHight(root->right);

    return left > right ? left + 1 : right + 1;
}

//走前序遍历,依次遍历每个节点,并求节点左子树与右子树的高度差 >1?
bool isBalanced(struct TreeNode* root) {
    if(root == NULL)
    return true;

    //比较当前节点左右子树高度差
    int left = TreeHight(root->left);   
    int right = TreeHight(root->right);
    if(abs(left-right) > 1)
    return false;

    if(isBalanced(root->left) == 0)  //遍历左子树
    return false;

    if(isBalanced(root->right) == 0)  //遍历右子树
    return false;

    return true; //代码到这说明它就是一颗平衡二叉树
}

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值