判斷一棵樹是否是二叉搜索樹


前兩天寫過一篇博文《二叉搜索樹基本操作實現》,為了更深入了解二叉搜索樹的性質,本文實現判斷一棵樹是否為二叉搜索樹算法。
 
二叉搜索樹的性質:
任意節點的鍵值一定大於其左子樹中的每一個節點的鍵值,並小於其右子樹中的每一個節點的鍵值。
構造二叉樹的節點定義為:
struct TreeNode{
    int data;
    TreeNode *left;
    TreeNode *right;
};

方法1 (錯誤)

對每一個節點,檢測其值是否大於左子樹節點,是否小於右子樹節點。思路很簡單,代碼實現如下:
bool isBST(TreeNode* root)
{
    if (root == NULL)
        return true;
    if (root->left != NULL && root->left->data> root->data)
        return false;
    if (root->right != NULL && root->right->data < root->data)
        return false;
    if (!isBST(root->left) || !isBST(root->right))
        return false;
    return true;
}
但是,這種方法是錯誤的,如下面例子,節點4大於根節點3,但上面函數檢測這棵樹是BST。
               3
            /      \
          2         5
       /     \
    1         4

方法2 

對每個節點,檢測其值是否大於左子樹的最大值,是否小於右子樹的最小值。思路正確,但效率較低,代碼實現如下:
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 : min;
    }
    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);
}
其中,maxValue及minValue函數,分別返回一棵非空二叉樹的最大值和最小值。 

方法3

方法2需要重復遍歷樹中的部分數據,故效率較低,如果只需每個節點遍歷一次,那么效率將大大提高。方法3的巧妙之處在於限定了子樹節點的值得范圍,從而每個節點只需遍歷一次。節點值的初始范圍可限定為TNT_MIN以及TNT_MAX。代碼實現如下:
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)
{
    return isBST02(root, INT_MIN, INT_MAX);
}

方法4

使用中序遍歷的方法實現:
1)對樹進行中序遍歷,將結果保存在temp數組中;
2)檢測temp數組是否為升序排列,如果是,則為BST,反之則不是。
此方法還可以進一步的優化,不用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;
}
二叉搜索樹的判斷是一個重要的算法,個人認為該算法的實現在考研或找工作中都非常重要,從這個算法可以考核到對二叉樹特別是二叉搜索樹的特性的了解。所以掌握好這個算法的思想和實現時非常必要的。
 

本文參考於https://www.2cto.com/kf/201506/408372.html,只是在其基礎上加上自己的一些見解,謝謝原作者。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM