給定一個根結點如何判斷一棵樹是否爲二叉搜索樹呢?下面我們用三種方式來處理這個問題
方法一:
根據二叉搜索樹的特徵,二叉搜索樹的中序遍歷應該爲一個有序集合
-
對樹進行中序遍歷,將結果保存在temp數組中
-
檢測temp數組是否爲升序排列,如果是,則爲BST,反之則不是
//這裏爲了好理解就直接使用遞歸寫
void inOrder(TreeNode* tmp, vector<int>& arr)
{
if(tmp->left)
inOrder(tmp->left, arr);
arr.push_back(tmp->value);
if(tmp->right)
inOrder(tmp->right, arr);
}
bool isBST(TreeNode* root)
{
vector<int> arr;
inOrder(root, arr);
int index = 1;
while(arr.size() > index){
if(arr[index] < arr[index - 1])
return false;
}
return true;
}
此方法還可以進一步的優化,不用temp數組,避免使用額外的內存開銷。在中序遍歷時使用靜態變量保存前驅節點,如果當前節點小於前驅節點,則該樹不是BST
bool isBST(TreeNode *root)
{
//靜態結點僅在第一次調用時創建
static TreeNode *prev;
if(root != NULL)
{
if(!isBST(root->left))
return false;
if(prev != NULL && root->data < prev->data)
return false;
prev = root;
if(!isBST(root->right))
return false;
}
return true;
}
方法二:
暴力法:該方法的思路最切合二叉搜索樹的概念(比較當前節點是否比左子樹最大節點大,比右子樹最小結點小)
int maxValue(TreeNode *root)
{
int max = root->data;
if(root->left != NULL)
{
int maxLeft = maxValue(root->left);
max = max > maxLeft ? max : maxLeft;
}
if(root->right != NULL)
{
int maxRight = maxValue(root->right);
max = max > maxRight ? max : maxRight;
}
return max;
}
int minValue(TreeNode *root)
{
int min = root->data;
if(root->left != NULL)
{
int minLeft = maxValue(root->left);
min = min > minLeft ? min : minLeft;
}
if(root->right != NULL)
{
int minRight = maxValue(root->right);
min = min > minRight ? min : minRight;
}
return min;
}
bool isBST(TreeNode *root)
{
if(root == NULL)
return true;
if(root->left != NULL && maxValue(root->left) > root->data)
return false;
if(root->right != NULL && minValue(root->right) < root->data)
return false;
return isBST(root->left) && isBST(root->right);
}
方法三:
討巧的方法,將樹結點值的範圍確定,所有節點的值滿足該範圍即爲二叉搜索樹
bool isBSTUtil(TreeNode *root, int min, int max)
{
if(root == NULL)
return true;
if(root->data < min || root->data > max)
return false;
return isBSTUtil(root->left, min, root->data - 1) && isBSTUtil(root->right, root->data + 1, max);
}
bool isBST(TreeNode *root)
{
//節點值的初始範圍可限定爲TNT_MIN以及TNT_MAX
return isBST02(root, INT_MIN, INT_MAX);
}