Binary Search Tree是一种搜索的数据结构,它的定义为:它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
本篇将展开一些Binary Search Tree的相关题型。
Validate Binary Search Tree
题目
验证是否为一颗二叉排序树。
思路
此题使用二叉排序树的定义即可,有两种方式:
- 中序遍历,检查每个节点是否按大小进行排布,同时左右子树是否为二叉排序树。
使用分治法,定义一个数据类存储子树中的最大值和最小值检查节点的顺序是否规范,同时检查左右子树是否为二叉排序树。
上述两种方法均为递归方法,因为同时要检验左右子树是否二叉排序树。
代码
这里只给出分治法的代码:
public boolean isValidBST(TreeNode root) {
ResultType r = validateHelper(root);
return r.is_bst;
}
private ResultType validateHelper(TreeNode root) {
if (root == null) {
return new ResultType(true, Integer.MIN_VALUE, Integer.MAX_VALUE);
}
ResultType left = validateHelper(root.left);
ResultType right = validateHelper(root.right);
if (!left.is_bst || !right.is_bst) {
// if is_bst is false then minValue and maxValue are useless
return new ResultType(false, 0, 0);
}
if (root.left != null && left.maxValue >= root.val ||
root.right != null && right.minValue <= root.val) {
return new ResultType(false, 0, 0);
}
return new ResultType(true,
Math.max(root.val, right.maxValue),
Math.min(root.val, left.minValue));
}
Binary Search Tree Iterator
题目
设计实现一个带有下列属性的二叉排序树的迭代器:
- 元素按照递增的顺序被访问
- next()和hasNext()的询问操作要求均摊时间复杂度是O(1)
思路
根据二叉排序树的定义,按递增的顺序被访问的遍历是中序遍历。而next()和hasNext()的均摊复杂度为O(1),则需要一个栈来记忆部分访问过的节点。
代码
public class BSTIterator {
private Stack<TreeNode> stack = new Stack<>();
private TreeNode curt;
public BSTIterator(TreeNode root) {
curt = root;
}
public boolean hasNext() {
return (curt != null || !stack.isEmpty());
}
public TreeNode next() {
while (curt != null) {
stack.push(curt);
curt = curt.left;
}
curt = stack.pop();
TreeNode node = curt;
curt = curt.right;
return node;
}
}
next()中的代码基本为中序遍历的代码,只是将已遍历过的节点进行存储使得均摊复杂度为O(1)。
Remove Node in Binary Search Tree
题目
题目为删除二叉排序树中的一个节点。
思路
首先,我们要找到这个节点。其次,重要的是把删除该节点的二叉树恢复成二叉排序树,这也是最关键和困难的一步。如果该节点没有子树,那么不需要恢复;如果该节点只有左子树或右子树,那么使用左子树或右子树的根节点直接代替该节点;如果该节点有两个子树,那么使用右子树中最小值节点(该节点没有左子树)进行代替即可,右子树最小值节点为第一个大于该节点的节点,所以这样做不会破坏二叉排序树的结构。
代码
这里只给出删除节点进行恢复的代码:
private void deleteNode(TreeNode parent, TreeNode node) {
if (node.right == null) {
if (parent.left == node) {
parent.left = node.left;
} else {
parent.right = node.left;
}
} else {
TreeNode temp = node.right;
TreeNode father = node;
while (temp.left != null) {
father = temp;
temp = temp.left;
}
if (father.left == temp) {
father.left = temp.right;
} else {
father.right = temp.right;
}
if (parent.left == node) {
parent.left = temp;
} else {
parent.right = temp;
}
temp.left = node.left;
temp.right = node.right;
}
}
右子树中最小值节点为最左边的值。
Search Range in Binary Search Tree
题目
给定两个值,求二叉排序树中值范围在这两个值中的节点。
思路
此题目用递归来实现。
代码
public ArrayList<Integer> searchRange(TreeNode root, int k1, int k2) {
results = new ArrayList<Integer>();
helper(root, k1, k2);
return results;
}
private void helper(TreeNode root, int k1, int k2) {
if (root == null) {
return;
}
if (root.val > k1) {
helper(root.left, k1, k2);
}
if (root.val >= k1 && root.val <= k2) {
results.add(root.val);
}
if (root.val < k2) {
helper(root.right, k1, k2);
}
}
上述代码根据二叉排序树的定义,如果当前节点的值大于k1则在该节点的左子树中进行搜索,如果当前节点的值小于k2则在该节点的右子树进行搜索,如果在此范围之外则不进行任何操作直接结束。