数据结构---BST 二分搜索树基本操作笔记

定义:

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;
            }
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值