目录

1.左右孩子递归检查

2.左右子树递归

3.限定值范围递归

4.使用中序遍历


在本系列的第一篇文章中,已经介绍过了二叉查找树(BST)的一些性质:

  • 节点的左子树中任意节点值小于根节点

  • 节点的右子树中任意节点值大于根节点

  • 左右子树都必须是二叉查找树,不允许存在重复节点

基于上面的这些性质,自然的就得到了这种判断方式:树中的每个节点都有一个特定的值。

假设树的节点定义为:

struct Node {int key;Node* left;Node* right;
};

1.左右孩子递归检查

对于每个节点,检测它的左孩子节点是否小于它,且右孩子节点是否大于它。

bool isBST(Node* node) {if (node == NULL)return true;//如果左孩子大于根节点,则不是BSTif (node->left != NULL && node->left->key > node->key)return false;//如果右孩子节点小于根节点,则不是BSTif (node->right != NULL && node->right->key < node->key)return false;//递归的判断if (!isBST(node->left) || !isBST(node->right))return false;//检测完毕,所有条件通过,则是BSTreturn true;
}

此方法虽然实现简单,但是,却是错误的。如下面例子所示,节点4处于根节点3的左子树中,但是函数检测到这棵树是BST。
        3
      /   \
    2     5
  /  \
1    4

2.左右子树递归

对于每个节点,检测左子树中的最大值是否比它小,而右子树的最小值比它大。

//如果是BST,则返回true
bool isBST(Node* node) {if (node == NULL)return true;//如果左子树最大值大于根节点,则返回falseif (node->left != NULL && maxValue(node->left) > node->key)return false;//如果右子树最小值小于根节点,则返回falseif (node->right != NULL && minValue(node->right) < node->key)return false;//递归判断if (!isBST(node->left) || !isBST(node->right))return(false);//所有检测都通过,是BSTreturn true;
}

其中,maxValue以及minValue函数,分别返回一颗非空树中的最大值和最小值。

此方法虽然正确,但是效率比较低,会多次重复的遍历树中的众多节点。

3.限定值范围递归

方法2因为要重复的遍历树中的部分数据,效率比较低,更好的方案是每个节点只遍历一次。

方法3的巧妙之处在于限定了子树中节点值的范围,从而每个节点只需访问一次。节点值的初始范围可限定为INT_MIN以及INT_MAX。

//判断是否为BST
bool isBST(Node* node)
{return(isBSTUtil(node, INT_MIN, INT_MAX));
}
//如果是一颗二叉查找树,且值范围在[min,max],则返回true
bool isBSTUtil(Node* node, int min, int max)

代码实现如下。

#include <iostream>struct Node {int key;Node* left;Node* right;
};bool isBSTUtil(Node* node, int min, int max);//判断是否为BST
bool isBST(Node* node) {return(isBSTUtil(node, INT_MIN, INT_MAX));
}//如果是一颗二叉查找树,且值范围在[min, max],则返回true
bool isBSTUtil(Node* node, int min, int max) {//空树也是BSTif (node == NULL)return true;//如果节点值违反了最大/最小约束条件,则不是BSTif (node->key < min || node->key > max)return false;//递归检查子树return  isBSTUtil(node->left, min, node->key - 1) &&isBSTUtil(node->right, node->key + 1, max);
}// 创建一个新的BST节点
Node* createNewNode(int item) {Node* temp = new Node;temp->key = item;temp->left = temp->right = NULL;return temp;
}int main() {/* tree1的定义4/   \2     5/ \1   3*/Node* root = createNewNode(4);root->left = createNewNode(2);root->right = createNewNode(5);root->left->left = createNewNode(1);root->left->right = createNewNode(3);if (isBST(root))std::cout << "tree1 is BST\n";elsestd::cout << "tree1 is not BST\n";/* tree2的定义4/   \2     5/     /1     3*/root = createNewNode(4);root->left = createNewNode(2);root->left->left = createNewNode(1);root->right = createNewNode(5);root->right->left = createNewNode(3);if (isBST(root))std::cout << "tree2 is BST\n";elsestd::cout << "tree2 is not BST\n";return 0;
}

运行结果:
tree1 is BST
tree2 is not BST

时间复杂度:O(n)
辅助空间:如果不考虑函数调用栈的大小,则为O(1), 否则为O(n)

4.使用中序遍历

1) 对树进行中序遍历,将结果保存在temp数组中。
3) 检测temp数组中元素是否为升序排列。如果是,则这棵树为BST。
时间复杂度:O(n)
方法4还可以进一步的优化,我们可以避免使用这个额外的数组。在中序遍历时,可以保存前驱节点,如果当前节点小于前驱节点,则这棵树不是BST。

#include <iostream>struct Node {int key;Node* left;Node* right;
};//判断是否为BST
bool isBST(Node* root) {static Node* prev = NULL;// 中序遍历这棵树,并保存前驱节点至prev中if (root) {if (!isBST(root->left))return false;// 检测节点值的合法性if (prev != NULL && root->key <= prev->key)return false;prev = root;//右子树return isBST(root->right);}return true;
}// 创建一个新的BST节点
Node* createNewNode(int item) {Node* temp = new Node;temp->key = item;temp->left = temp->right = NULL;return temp;
}int main() {/* tree1的定义4/   \2     5/ \1   3*/Node* root = createNewNode(4);root->left = createNewNode(2);root->right = createNewNode(5);root->left->left = createNewNode(1);root->left->right = createNewNode(3);if (isBST(root))std::cout << "tree1 is BST\n";elsestd::cout << "tree1 is not BST\n";/* tree2的定义4/   \2     5/     /1     3*/root = createNewNode(4);root->left = createNewNode(2);root->left->left = createNewNode(1);root->right = createNewNode(5);root->right->left = createNewNode(3);if (isBST(root))std::cout << "tree2 is BST\n";elsestd::cout << "tree2 is not BST\n";return 0;
}

运行结果:
tree1 is BST
tree2 is not BST

更多参考:
http://en.wikipedia.org/wiki/Binary_search_tree
http://cslibrary.stanford.edu/110/BinaryTrees.html

二叉查找树(5) - 判断一棵二叉树是否为BST相关推荐

  1. python代码判断两棵二叉树是否相同

    python代码判断两棵二叉树是否相同 给定两个二叉树,编写一个函数来校验它们是否相同.如果两个树在结构上相同,并且结点具有相同的值,则认为它们是相同的. 判断两个二叉树是否是相同的,相同的依据是 二 ...

  2. 牛客题霸 [ 判断一棵二叉树是否为搜索二叉树和完全二叉树] C++题解/答案

    牛客题霸 [ 判断一棵二叉树是否为搜索二叉树和完全二叉树] C++题解/答案 题解: 搜索二叉树满足以下性质: 1.非空左子树的所以键值小于其根节点的键值 2.非空右子树的所有键值大于其根节点的键值 ...

  3. 判断一棵二叉树是否为完全二叉树-Java

    分享一个大牛的人工智能教程.零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来!请轻击http://www.captainbed.net package live.every.day.Pro ...

  4. Python算法——判断两棵二叉树是否相等

    要求: 如何判断两颗树是否相等?(两棵树相等是指这两课树有着相同的结构,并且在相同位置上的结点有相同的值) 分析: 如果两颗二叉树root1, root2相等, 那么root1和root2结点的值相同 ...

  5. 判断一棵二叉树是否为搜索二叉树、完全二叉树、平衡二叉树(java)

    平衡二叉树的解法:主要是求出二叉树的高度,若根节点的左子树的高度与右子树的高度差小于等于1,则表示该二叉树为平衡二叉树 public static class Node{public int valu ...

  6. 判断一棵二叉树是否为平衡二叉树

    1.先给出树节点信息 typedef struct tree{struct tree *lchild;struct tree *rchlid;int data; }tree,* Bitree; 2.原 ...

  7. 【面试】判断一棵二叉树是否为二叉排序树

    一.描述 给定一棵二叉树,如何判断一棵树是否是二叉排序树.给出树结点定义如下 class TreeNode {int key;TreeNode left;TreeNode right;public T ...

  8. 判断两棵二叉树是否同构,三种实现方式(递归、队列、堆栈)

    一.同构的概念: 给定两棵二叉树 T1 和 T2,如果T2可以通过若干次左右孩子互换就变成T1,那么我们称这两棵树是同构的 例1:下图两棵树同构,因为对T2,交换A左右孩子:交换B左右孩子,交换G左右 ...

  9. 如何判断一棵二叉树是完全二叉树(1)

    完全二叉树的定义: 一棵二叉树,除了最后一层之外都是完全填充的,并且最后一层的叶子结点都在左边. 一个直观的想法, 就是观察一棵完全二叉树,来分析它到底有什么特征. 方法1: 按层遍历二叉树, 从每层 ...

最新文章

  1. GPT-3数学不及格,愁坏伯克利团队,于是他们出了12500道数学作业
  2. I.MX6 Power off register hacking
  3. Linux SPI总线和设备驱动架构之三:SPI控制器驱动
  4. java发送串口命令_如何發送命令到串口(JAVA + RXTX)
  5. BZOJ5358: [Lydsy1805月赛]口算训练
  6. 神经网络与深度学习——TensorFlow2.0实战(笔记)(四)(python文件)
  7. leetcode 26 --- removeDuplicates
  8. ROS笔记(40) 通讯节点
  9. Redis内存回收和持久化策略
  10. 日历控件如何切换语言 vant_看看甘特图控件VARCHART XGantt的亮点
  11. [补档]noip2019集训测试赛(十二)
  12. Android Studio开发学习 - 1. 添加Activity
  13. Redis+Keepalived内存数据库集群配置
  14. php JS 导出表格特殊处理
  15. Android自定义ToolBar布局
  16. 认识linux,走进开源世界。
  17. git 设置全局代理_git 代理配置
  18. csgo自建局域网服务器,csgo怎么创建局域网游戏
  19. 流体力学示例 Python 分析
  20. SSH 命令的11种用法

热门文章

  1. onethink中修改ucenter用户的密码
  2. 2823【例9.15】潜水员
  3. (原创) 脚踏实地学Java之:基础篇
  4. 曾经的Uber自动驾驶,其实成败只在一念之间?
  5. 最新selenium3匹配的火狐版本
  6. 114网速测试发型软件,在线网速测试器
  7. 微信小程序 错误记录
  8. redis续期_redis分布式锁自动延长过期时间
  9. 软链接(Soft Link,符号链接)和硬链接(Hard Link)。
  10. android 重力感应的使用