定义:
1.是一个二叉树
2.每个树的左子树的所有节点 < 根节点 < 所有右子树的节点值(当前树中所有子树也遵循这个给规则)
3.存储结点必须具备可以比较的能力(要么实现了Comparable接口,要么传入比较器)
前置代码:
class Node {
int val;
Node left;
Node right;
public Node(int val) {
this.val = val;
}
}
public class MyBinSearchTree {
private int size;
// 当前根节点
private Node root;
}
插入:
新插入的元素都一定在树的叶子节点进行插入操作。不断和数根节点去比大小,若小就在左树中添加,若大就在右子树添加;
动态图解:
* 向当前以root为根的BST中插入一个新的元素,返回插入后的根结点。
* 时间复杂度:
* 平均:O(logn) --> 树的插入
* 最坏情况:插入一个完全有序的集合,此时的二分搜索树变成了单支树,相当于链表 O(N)
public void add(int val) {
root = add(root, val);
}
/**
* 向当前以root为根的BST中插入一个新的元素,返回插入后的根结点。
* 时间复杂度:
* 平均:O(logn) --> 树的插入
* 最坏情况:插入一个完全有序的集合,此时的二分搜索树变成了单支树,相当于链表 O(N)
* @param root
* @param val
* @return
*/
private Node add(Node root, int val) {
// 如果此时树为空,node就是树根
if (root == null) {
Node node = new Node(val);
size++;
return node;
}
// 如果插入值小于当前根节点的值,就插入左子树中
if (val < root.val) {
root.left = add(root.left, val);
}
// 如果插入值大于当前根节点的值,就插入右子树中
if (val > root.val) {
root.right = add(root.right, val);
}
return root;
}
查找:
不断递归的去和树的树根结点相比,相等就找到了;小于继续在左树中找;大于在右树中找;若root==null,不存在。
* 时间复杂度:
* 平均:O(logn) --> 树的插入
* 最坏形况:退化为链表 O(N)
public boolean contains(int val) {
return contains(root, val);
}
/**
* 判断以当前root为根的BST中是否包含指定值val,存在返回true,否则返回faLse
* 时间复杂度:
* 平均:O(logn) --> 树的插入
* 最坏形况:退化为链表 O(N)
* @param root
* @param val
* @return
*/
private boolean contains(Node root, int val) {
// 如果根节点为空
if (root == null) {
return false;
}
// 当前根结点的值等于val
if (val == root.val) {
return true;
} else if (val < root.val) {
// 当前根结点的值小于val
return contains(root.left, val);
} else {
// 当前根结点的值大于val
return contains(root.right, val);
}
}
按照先序遍历打印BST:
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
generateBSTString(root,0,sb);
return sb.toString();
}
/**
* 按照先序遍历的方式,将BST的节点值存入sb之中。
* @param root
* @param height
* @param sb
*/
private void generateBSTString(Node root, int height, StringBuilder sb) {
if (root == null) {
// 当前节点为空返回 高度 和 NULL
sb.append(currentHeight(height)).append("NULL\n");
return;
}
sb.append(currentHeight(height)).append(root.val).append("\n");
// 递归打印左子树
generateBSTString(root.left,height + 1,sb);
// 递归打印右子树
generateBSTString(root.right,height + 1,sb);
}
/**
* 按照当前节点的高度打印 *
* @param height
* @return
*/
private String currentHeight(int height) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < height; i++) {
sb.append("*");
}
return sb.toString();
}
找到最大值和最小值:
因为BST中,最小值一定在左子树,最大值一定在右子树,所以在找Min和Max时只需要在左右子树中递归查询。
找最大值:
public int findMax() {
if (size == 0) {
throw new NoSuchElementException("BST is empty!");
}
return getMax(root).val;
}
/**
* 在以root为根节点BST中找最大值
*
* @param root
* @return
*/
private Node getMax(Node root) {
// 因为BST中最大值一定在左子树中,所以只需递归右子树
if (root.right == null) {
return root;
}
return getMax(root.right);
}
找最小值:
public int findMin() {
if (size == 0) {
throw new NoSuchElementException("BST is empty!");
}
return getMin(root).val;
}
/**
* 在以root为根节点BST中找最小值
*
* @param root
* @return
*/
private Node getMin(Node root) {
// 因为BST中最小值一定在左子树中,所以只需递归左子树
if (root.left == null) {
return root;
}
return getMin(root.left);
}
删除:
删除最大值:
public int removeMax() {
if (size == 0) {
throw new NoSuchElementException("BST is empty!");
}
Node minNode = getMax(root);
root = removeMax(root);
return minNode.val;
}
/**
* 传入一个以root为根的BST,就能删除其中最大值,返回删除后的树根节点
*
* @param root
* @return
*/
private Node removeMax(Node root) {
if (root.right == null) {
// 此时root就是要删除的
Node left = root.left;
size--;
return left;
}
root.right = removeMax(root.right);
return root;
}
删除最小值:
public int removeMin() {
if (size == 0) {
throw new NoSuchElementException("BST is empty!");
}
Node minNode = getMin(root);
root = removeMin(root);
return minNode.val;
}
/**
* 传入一个以root为根的BST,就能删除其中最小值,返回删除后的树根节点
*
* @param root
* @return
*/
private Node removeMin(Node root) {
if (root.left == null) {
// 此时root就是要删除的
Node right = root.right;
size--;
return right;
}
// 根节点不为空,说明要删除的最小值一定在左子树上
root.left = removeMin(root.left);
return root;
}
删除任意值:
public void removeVal(int val) {
if (size == 0) {
throw new NoSuchElementException("BST is empty!");
}
root = removeVal(root, val);
}
private Node removeVal(Node root, int val) {
if (root == null) {
throw new NoSuchElementException("val does not exist in BST!");
} else if (val < root.val) {
root.left = removeVal(root.left, val);
return root;
} else if (val > root.val) {
root.right = removeVal(root.right, val);
return root;
} else {
// 此时BST不为空,且 root.val == val;
// 确定此时的root就是要删除的节点
if (root.left == null) {
// 当前root节点的左子树为空,直接删除,返回右子树树根节点
Node right = root.right;
size--;
return right;
} else if (root.right == null) {
// 当前root节点的右子树为空,直接删除,返回左子树树根节点
Node left = root.left;
size--;
return left;
} else {
// 左右子树都不为空时,找到后继或前驱节点
// 后继:就是当前root节点下的右子树中的最小值
// 前驱:就是当前root节点下的左子树中的最大值
// 以后继为例:
Node successor = getMin(root.right);
// 当前root节点下的左右子树融合。
// 1.现在右子树中删除这个值。
successor.right = removeMin(root.right);
// 2.连接左子树 root.left
successor.left = root.left;
// 返回后继
return successor;
}
}
}