前兩天寫過一篇博文《二叉搜索樹基本操作實現》,為了更深入了解二叉搜索樹的性質,本文實現判斷一棵樹是否為二叉搜索樹算法。
二叉搜索樹的性質:
任意節點的鍵值一定大於其左子樹中的每一個節點的鍵值,並小於其右子樹中的每一個節點的鍵值。
構造二叉樹的節點定義為:
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,只是在其基礎上加上自己的一些見解,謝謝原作者。