1 中序遍历和搜索树原理
二叉搜索树按照中序遍历正好是一个递增序列。其比较规范的定义是:
- 若它的左子树不为空,则左子树上所有节点的值均小于它的根节点的值;
- 若它的右子树不为空,则右子树所有节点的值均大于它的根节点的值;
- 它的左、右子树也分别为二叉搜索树,比如下面的例子:
这两棵树的中序遍历分别是[1, 2, 3, 4, 5, 6, 7, 8, 9]
和[6, 7, 8, 9]
,都是二叉搜索树。
2 二叉搜索树中搜索特定值
力扣700题,给定二叉搜索树(BST)的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。
比如target为3,给定二叉搜索树:
5
/ \
3 4
/ \
1 2
应该返回如下子树:
3
/ \
1 2
2.1 递归实现
使用递归来实现,先来分析一下有哪些情况:
- 如果根节点
root === null
或者root.val === target
就直接返回根节点; - 如果
target < root.val
,说明比右子树的值小,去根节点的左子树进行查找searchBST(root.left, target)
; - 如果
target > root.val
,说明比左子树的值大,去根节点的右子树进行查找searchBST(root.right, target)
。
递归完整代码如下:
// 递归法
function searchBST(root, target) {
// 如果根节点为空或者root.val === target,直接返回root
if (root === null || root.val === target) {
return root;
}
// 如果target < root.val,进入根节点的左子树查找
// 如果target > root.val,进入根节点的右子树查找
return target < root.val ? searchBST(root.left, target) : searchBST(root.right, target);
}
2.2 迭代实现
迭代逻辑:
- 如果根节点
root === null
或者root.val !== target
,进入下面的判断- 如果
target < root.val
,说明比右子树的值小,去根节点的左子树进行查找,root = root.left
; - 如果
target > root.val
,说明比左子树的值大,去根节点的右子树进行查找,root = root.right
- 如果
迭代完整代码如下:
// 迭代法
function searchBST(root, target) {
// 如果根节点为空或者target !== root.val
while (root !==null && target !== root.val) {
// 如果target < root.val,进入根节点的左子树查找,root = root.left
// 如果target > root.val,进入根节点的右子树查找,root = root.right
root = (target < root.val ? root.left : root.right);
}
return root;
}
3 验证二叉搜索树
力扣98题,给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。有效二叉树定义如下:
- 节点的左子树只包含 小于 当前节点的数。
- 节点的右子树只包含 大于 当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
分析:根据题目以及中序遍历的特性,可以知道二叉搜索树中序遍历得到的序列是一个升序序列,要判断是否是一个有效二叉树,只需要在中序遍历的时候一边遍历一边检查当前节点的值是否大于前一个遍历到的节点值即可。
3.1 递归实现
递归实现,代码如下:
function isValidBST(root) {
let pre = Number.MIN_SAFE_INTEGER;
return validBST(root);
function validBST(node) {
if (node === null) {
return true;
}
// 如果左子树某个元素不满足要求就退出
if (!validBST(node.left)) {
return false;
}
// 如果当前节点值≤中序遍历前一个节点的值,不能满足二叉搜索树条件
if (node.val <= pre) {
return false;
}
pre = node.val;
return validBST(node.right);
}
}
3.2 迭代实现
测试用例的最小节点有可能是javascript
中的最小值,因此初始化preVal = -Infinity
。
function isValidBST(root) {
const nodeStack= [];
let preVal = -Infinity;
while (nodeStack.length !== 0 || root !== null) {
while (root !== null) {
nodeStack.push(root);
// 先遍历左子树
root = root.left;
}
// 比较左子树中间根节点与前一个节点的值,如果小与前一个节点值,说明不是二叉搜索树
root = nodeStack.pop();
if (root.val <= preVal) {
return false;
}
preVal = root.val;
// 再遍历右子树
root = root.right;
}
return true;
}