这里先简单介绍一下二叉查找树的性质: 递归定义节点的左子树中任意节点值小于根节点的值,节点的右子树中任意节点值大于根节点,且当前节点左右子树都必须是二叉查找树,不允许存在重复节点。
假设:
节点的数据结构:
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;
}
这里我们可以举一个非常直接的反例:
方法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);