判断一棵二叉树是否为二叉搜索树(BST)

这里先简单介绍一下二叉查找树的性质: 递归定义节点的左子树中任意节点值小于根节点的值,节点的右子树中任意节点值大于根节点,且当前节点左右子树都必须是二叉查找树,不允许存在重复节点。
假设:

节点的数据结构:

struct node
{
    int value;
    node* left;
    node* right;
};

方法1(错误示范:自己踩的坑)

首先BST是一个递归定义:这样我们首先想到用递归的方式进行判断:

//对于每个节点,检测它的左孩子节点是否小于它,且右孩子节点是否大于它。
bool isBST(node* root)
{
  if (root == NULL)
    return true;

  //如果左孩子大于根节点,则不是BST
  if (root->left != NULL && root->left->key> root->key)
    return false;

  //如果右孩子节点小于根节点,则不是BST
  if (root->right != NULL && root->right->key < root->key)
    return false;

  //递归的判断
  if (!isBST(root->left) || !isBST(root->right))
    return false;

  //BST
  return true;
}

这里我们可以举一个非常直接的反例:
《判断一棵二叉树是否为二叉搜索树(BST)》

方法2

根据最基础的定义,我们在判断每棵子树的时候返回左子树的最大值小于当前节点值,同时右子树的最小值大于当前节点值,是的,这样会出现某些节点进行多次判断,当然我们可以通过添加数组结构来保存中间结果加快计算

二叉树的最大值出现在最右侧的位置,最小值出现在最左侧的部分

int maxValue(node* root)
{
    if(root == NULL)
        return INT_MAX
    while(root -> right)
        root = root -> right;
    return root -> value;
}
int minValue(node* root)
{
    if(root == NULL)
        return INT_MIN
    while(root -> left)
        root = root -> left;
    return root -> value;
}
bool isBST(node* root )
{
        if (root == NULL)
               return true;
        //如果左子树最大值大于根节点,则返回false
        if (root->left != NULL && maxValue(root->left) > node->value)
               return false;
        //如果右子树最小值小于根节点,则返回false
        if (root->right != NULL && minValue(root->right) < node->value)
               return false;

        //递归判断
        if (!isBST(root->left) || !isBST(root->right))
               return false;
        return true;
}

方法3

我们知道,二叉搜索树的中序遍历是一个递增序列,所以我们只需要把这个中序遍历保存下来,然后判断这是个递增序列即可:

void LDR(node * root, vector<int>& inorder)
{
    if(root == NULL)
        return;
    LDR(root -> left);
    inorder.push_back(root -> value);
    LDR(root -> right);
}
bool isBST(node* root)
{
    vector<int> inorder;
    LDR(root);
    for(int i = 1; i < inorder.size(); ++i)
        if(inorder[i - 1] >= inorder[i])
            return false;
    return true;
}

方法4

其实用的还是之前的中序遍历的方法,但我们实际上也看到了,在方法3中判断合法的方法也是在把现在的值跟前一个值进行比较

//保存之前访问过的节点的值,判断当前访问的小于之前保存的值
int lastVisited = INT_MIN;
bool isBST(node * root)
{
    if(root == NULL)
        return true;
    //判断左子树
    if(!LDR(root -> left))
        return false;
    if(root -> value <= lastVisited)
        return false;
    lastVisited = root -> value;
    //判断右子树
    if(!LDR(root -> right))
        return false;
    return true;
}

方法5

这里其实用的是是前序遍历,当前节点的值是左子树的最大值,同时是右子树的最小值,所以我们接下来进行递归判断即可

bool isBST(node *root, int maxVal, int minVal)  
{  
    if (root == NULL)  
        return true;  
    if (root->val < minVal || root->val >= maxVal)  
        return false;  
    if (!preOrder(root->left, root->val, minVal) || !preOrder(root->right, maxVal, root->val))  
        return false;  
    return true;  
}  
isBST(root, INT_MAX, INT_MIN);

参考博客:http://blog.csdn.net/fly_yr/article/details/52172839

    原文作者:Feng某人
    原文地址: https://blog.csdn.net/qq_30490125/article/details/53135274
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞