leetcode【数据结构简介】《二叉搜索树》卡片——二叉搜索树简介

Authur Whywait 做一块努力吸收知识的海绵
想看博主的其他所有leetcode卡片学习笔记链接?传送门点这儿

二叉搜索树是二叉树的一种特殊形式。 二叉搜索树具有以下性质:每个节点中的值必须大于(或等于)其左侧子树中的任何值,但小于(或等于)其右侧子树中的任何值。

二叉搜索树的定义

二叉搜索树BST)是二叉树的一种特殊表示形式,它满足如下特性:

  1. 每个节点中的值必须大于(或等于)存储在其左侧子树中的任何值。
  2. 每个节点中的值必须小于(或等于)存储在其右子树中的任何值。

下图是一个二叉搜索树的例子。
在这里插入图片描述
像普通的二叉树一样,我们可以按照前序、中序和后序来遍历一个二叉搜索树。

但是值得注意的是,对于二叉搜索树,我们可以通过中序遍历得到一个递增的有序序列。因此,中序遍历是二叉搜索树中最常用的遍历方法

验证二叉搜索树🚩

给定一个二叉树,判断其是否是一个有效的二叉搜索树。

假设一个二叉搜索树具有如下特征:

  • 节点的左子树只包含小于当前节点的数。
  • 节点的右子树只包含大于当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

在这里插入图片描述

分析 1

  • 由前文所述二叉搜索树在中序遍历下的特殊现象,脑子蹦出来的第一个方法(反正这是我的第一个想法)就应该是中序遍历观察其序列。

至于如何用各种姿势遍历一个树,详情请点击传送门

Tips

值得注意的是,这里的二叉搜索树有其特殊性:每个节点中的值必须大于或等于存储在其左侧子树中的任何值;每个节点中的值必须小于或等于存储在其右子树中的任何值。

这是和我们前面介绍中略有区别的一点(也不知道你在看前文时有没有注意到这点)

这是我们需要注意的细节,不然作为特例判断时容易出错。

代码实现以及执行结果

利用中序遍历二叉搜索树会得到一个单调递增序列的性质,我另开了一个辅助数组,存储使用递归方法中序遍历得到的序列。

如果出现flag为false(即出现一个小于序列末尾的数想加入序列,我们就让标志flag为false),我们就层层返回。不再执行后面的语句。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

int array[10000] = {0}, count=0;;
bool flag = 1;

void isBST(struct TreeNode* root){
    if(!root || !flag) return;

    isBST(root->left);

    if(count>0 && array[count-1]>=root->val) flag = false;
    else array[count++] = root->val;

    isBST(root->right);

    return;
}


bool isValidBST(struct TreeNode* root){
    count = 0; flag = 1;	//初始化
    isBST(root);
    return flag;
}

在这里插入图片描述

分析 2

  • 上面的方法需要有一个一维数组来存储遍历到的序列(当然也可以不用全局变量,不过需要动态申请空间,然后传递的时候需要多传递几个参数,比较麻烦一些)。显然,应该有更好的方法来处理这个问题。(虽然题目中没有时间复杂度和空间复杂度的要求,但是谁都想整个最优的不是吗?)
  • 思索上面的方法,是有使用一个数组来存储中序遍历到的序列,但是真正涉及到的比较操作,其实只有序列末尾的数和待加入序列的数这两者的比较,所以我们只要用一个变量把最后一个数存储下来不就好了吗?
  • 需要注意的是,作为中序遍历到的第一个元素,我们需要的操作是将其赋值给temp(temp作为中序遍历到的上一个元素),而非比较判断是非。这也是temp没有初始化的原因。
  • 下面是修改后的代码:
bool flag = true, isfirst = true;
int temp;
void isBST(struct TreeNode* root){
    if(!root || !flag) return;

    isBST(root->left);

    if(!isfirst && temp>=root->val) flag = false;
    else{
        temp = root->val;
        isfirst = false;
    }

    isBST(root->right);
    return;
}


bool isValidBST(struct TreeNode* root){
    isfirst = true, flag = true; //以防万一,此处初始化
    isBST(root);
    return flag;
}

总结

最后查看官方题解,发现思路大同小异。bingo~

二叉搜索树迭代器🚩

实现一个二叉搜索树迭代器。你将使用二叉搜索树的根节点初始化迭代器。

调用 next() 将返回二叉搜索树中的下一个最小的数。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
/**
 * Your BSTIterator struct will be instantiated and called as such:
 * BSTIterator* obj = bSTIteratorCreate(root);
 * int param_1 = bSTIteratorNext(obj);
 
 * bool param_2 = bSTIteratorHasNext(obj);
 
 * bSTIteratorFree(obj);
*/

分析

回想我们之前在前面学习的中序遍历二叉树,无非就是将二叉树中序遍历一遍,然后存储到一个数组里面,相较于此题,就是每次next一下,就将头指针后移一个元素。

然而,我们存储那个序列,应该用什么数据结构呢?

用一维数组?也曾考虑过,但是题目直接丢给你一个结构体,意思是我们需要存储到一个结构体里头(当然结构体里面的具体内容由我们自己定义)。其实也不是不能实现,我们先把它存储到数组里头,然后再把数组搞成一个链表。(至于链表如何实现迭代器的功能?我认为可以这样:每次输出头节点的val,然后删除头节点;至于判断就是判断头节点是否为NULL;至于释放就直接顺着链表逐个释放就好啦~)

看到这里,你心里肯定有个小人这么在嘀咕:烦不烦?转来转去的?

想想时间复杂度和空间复杂度,就知道此举措必定是一个憨憨行为。

那用队列,让他们按照中序遍历的顺序入队。至于next操作就是输出头指针,然后头指针后移···

如果用栈,如果按照中序遍历的顺序入了栈,我们如何才可以对栈底的元素进行操作?(这明显和的性质不符嘛)

如此一路分析下来,似乎我们只能用队列了,两个指针,动来动去好麻烦··· 可是也没别的办法了····

BUT!!!

如果我们用栈,不用中序遍历,而是反着来中序遍历呢?

栈顶元素不就是我们需要的了么?

不要668,不要998,一个栈顶指针解决一切烦恼!

代码实现以及执行结果

typedef struct Stack{
    int val[10000];
    int top;
} BSTIterator;

void reverseInorder(struct TreeNode* root, BSTIterator* obj){
    if(!root) return;
    reverseInorder(root->right, obj);
    obj->val[obj->top++] = root->val;
    reverseInorder(root->left, obj);
}

BSTIterator* bSTIteratorCreate(struct TreeNode* root) {
    if(!root) return NULL;

    BSTIterator* obj = (BSTIterator *)malloc(sizeof(BSTIterator));
    if(!obj) return NULL;
    obj->top = 0;

    reverseInorder(root, obj);
    return obj;
}

/** @return the next smallest number */
int bSTIteratorNext(BSTIterator* obj) {
    return obj->val[(obj->top--)-1];
}

/** @return whether we have a next smallest number */
bool bSTIteratorHasNext(BSTIterator* obj) {
    return (obj)&&(obj->top>0);
}

void bSTIteratorFree(BSTIterator* obj) {
    if(obj && obj->top) free(obj->val);
    free(obj);
}

在这里插入图片描述

报错

身在代码中,报错少不了。

下面是在写此题代码中遇到的报错,请点击传送门

都看到这里了,确定不点个👍再走? (~ ̄(OO) ̄)ブ (疯狂暗示.jpg)

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

AuthurLEE

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

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

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

打赏作者

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

抵扣说明:

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

余额充值