小白学C语言数据结构之二叉树(二)

常见题

二叉树这里主要是二叉树的递归套路

二叉树有一个潜台词:

给定头节点,左树和右树可以返回信息

寻找直接后继

意思是,给定二叉树中随机一个节点(这个节点包含指向其父树的指针),找到其在中序遍历中的下一个节点

解法1:暴力遍历

既然有指针,就根据一个节点找到整棵树,在做一遍中序遍历

coding

struct TreeNode{
    int value;
    struct TreeNode* left;
    struct TreeNode* right;
    struct TreeNode* parent;
};
struct TreeNode* whole(struct TreeNode* node){
    if(node ==NULL){
        return NULL;
    }
    struct TreeNode* p = (struct TreeNode*)malloc(sizeof(struct TreeNode));
    p = node;
    if(p->parent != NULL){
        p = p->parent;
    }
    return p;
}                     
struct TreeNode* find(struct TreeNode* node){
    if(struct TreeNode* node == NULL){
        return NULL;
    }
    struct TreeNode* head = (struct TreeNode*)malloc(sizeof(struct TreeNode));
    head = whole(node);      // 现在是头指针辣
    // 中序遍历
    find(head->left);
    printf("%d  ", head->value);
    find(head->right);
    
    ....
// 倒进数组...找下标...
    

解法2:找规律,再递归

如图,两种情况

coding试试

struct TreeNode{
    int value;
    struct TreeNode* left;
    struct TreeNode* right;
    struct TreeNode* parent;
};
struct TreeNode* getLeftMost(struct TreeNode* node){
    if(node ==NULL){
        return node;
    }
    while(node->left !=NULL){  // 只要有左子树 就一直往上
        node = node->left;
    }
    return node;
}
struct TreeNode* get(struct TreeNode* node){
    if(node==NULL){
        return node;
    }
    if(node->right != NULL){
        return getLeftMost(node->right);     // 一直往上找 
    }
    else{
        struct TreeNode* next = (struct TreeNode*)malloc(sizeof(struct TreeNode));
        next = node->parent;
        while(parent!= NULL && parent->left != node/*parent->right == node*/){
            next = parent;
            parent = node->parent;
        }
        return parent;
    }
}

判断是否平衡二叉树

平衡:左子树和右子树的高度差不超过1

所以要满足

  1. 左树平衡 右树平衡

  1. 左右高度差不超过1

所以这道题对左右树的要求相同:

需要两个信息 1. 是否平衡 2. 树高度

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

// 二叉树结点的定义
struct TreeNode {
    int val;
    TreeNode *left, *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

// 返回给定节点为根节点的二叉树的高度
int getHeight(TreeNode* root) {
    if (root == NULL) {
        return 0;
    }
    return max(getHeight(root->left), getHeight(root->right)) + 1;
}

// 判断给定节点为根节点的二叉树是否为平衡二叉树
bool isBalanced(TreeNode* root) {
    if (root == NULL) {
        return true;
    }
    int leftHeight = getHeight(root->left);
    int rightHeight = getHeight(root->right);
    if (abs(leftHeight - rightHeight) > 1) {
        return false;
    } else {
        return isBalanced(root->left) && isBalanced(root->right);
    }
}

判断是否搜索二叉树

题目:返回满足搜索二叉树的头节点

特点:每一颗子树 左树都比root小,右树都比root大(感觉好像小根堆)

思路:

既然要判断是不是左树大于根、右树大于根。而左右树又不需要比较...

就是说 左比根 右比根

#include<iostream>
using namespace std;

// 二叉树结点的定义
struct TreeNode {
    int val;
    TreeNode *left, *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

// 用于记录最大BST的信息
struct BSTInfo {
    bool isBST;     // 是否是BST
    int minVal;     // 最小值
    int maxVal;     // 最大值
    TreeNode *root; // BST的根节点
    int size;       // BST的节点数
};

// 递归函数,返回以root为根节点的BST的信息
BSTInfo getBSTInfo(TreeNode* root) {
    if (root == NULL) {
        return { true, INT_MAX, INT_MIN, NULL, 0 };
    }
    BSTInfo left = getBSTInfo(root->left);
    BSTInfo right = getBSTInfo(root->right);
    if (left.isBST && right.isBST && left.maxVal < root->val && root->val < right.minVal) {
        // 以root为根节点的树是BST
        return { true, min(left.minVal, root->val), max(right.maxVal, root->val), root, left.size + right.size + 1 };
    } else {
        // 以root为根节点的树不是BST
        // 返回左右子树中最大的BST
        if (left.size > right.size) {
            return left;
        } else {
            return right;
        }
    }
}

// 返回给定二叉树中最大的BST的头节点
TreeNode* getMaxBST(TreeNode* root) {
    return getBSTInfo(root).root;
}

总结

递归套路真的不太容易...

有思路容易

理解难

coding更难...

多画点脑图,一步一步拆解去理解可能更方便一些..

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值