Java版高级数据结构算法 - BST树

知识的学习在于点滴记录,坚持不懈;知识的学习要有深度和广度,不能只流于表面,坐井观天;知识要善于总结,不仅能够理解,更知道如何表达!

BST二叉搜索树是面试中常考的问题,因为不涉及旋转操作和节点着色,因此比AVL和红黑树实现起来要简单很多,成为了笔试面试中写代码常见的考点。这篇文章分享一下BST树以及常见的BST树相关的笔试面试常考题目。

二分查找

对于一组有序的序列,进行搜索的时候可以采用二分搜索来提高效率,对比线性搜索的时间复杂度是O(n),对于有序序列的二分搜索时间复杂度是O( log ⁡ 2 n \log_2n log2n),因此搜索效率比较高,下面提供递归以及非递归的二分搜索代码实现:

非递归版本

/**
 * 二分查找的非递归实现,在有序的list集合元素中,进行二分搜索,查找val值
 * @param list
 * @return
 */
private static <T extends Comparable<T>>
T nonrecur_binarysearch(List<T> list, T val) {
    int first = 0;
    int last = list.size()-1;
    int middle = 0;
    T data = null;

    while(first <= last){
        middle = (first + last) / 2;
        data = list.get(middle);
        if(val.compareTo(data) < 0){
            last = middle-1;
        } else if(val.compareTo(data) > 0){
            first = middle+1;
        } else {
            return data;
        }
    }

    return null;
}

递归版本

/**
 * 二分查找的递归实现,在有序的list集合元素中,进行二分搜索,查找val值
 * @param list
 * @param val
 * @return
 */
private static <T extends Comparable<T>>
T recur_binarysearch(List<T> list, T val) {
    return recur_binarysearch(list, 0, list.size()-1, val);
}

/**
 * 二分查找的递归具体实现过程
 * @param list
 * @param i
 * @param j
 * @param val
 * @return
 */
private static <T extends Comparable<T>>
T recur_binarysearch(List<T> list, int i, int j, T val) {
    if(i > j){
        return null;
    }

    int middle = (i + j) / 2;
    T data = list.get(middle);
    if(val.compareTo(data) < 0){
        return recur_binarysearch(list, i, middle-1, val);
    } else if(val.compareTo(data) > 0){
        return recur_binarysearch(list, middle+1, j, val);
    } else {
        return data;
    }
}

测试代码如下:

public static void main(String[] args) {
    List<Integer> list = new ArrayList<>();
    Random rand = new Random(50);
    for(int i=0; i<20; ++i){
        list.add(rand.nextInt(100));
    }

    Collections.sort(list);
    System.out.println("排序后的元素序列:" + list);

    Integer data = nonrecur_binarysearch(list, 7);
    System.out.println(data);

    data = recur_binarysearch(list, 28);
    System.out.println(data);
}

BST二叉搜索树

上面二分搜索的过程就是BST树搜索的过程,BST树的每一个节点最多有两个孩子,而且左孩子的值 < 父节点的值 < 右孩子的值,下面定义BST树相关的类:

/**
 * BST树节点的实现
 * @param <T>
 */
class BSTNode<T extends Comparable<T>>{
    private T data;
    private BSTNode<T> left;
    private BSTNode<T> right;

    public BSTNode(T data) {
        this(data, null, null);
    }

    public BSTNode(T data, BSTNode<T> left, BSTNode<T> right) {
        this.data = data;
        this.left = left;
        this.right = right;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public BSTNode<T> getLeft() {
        return left;
    }

    public void setLeft(BSTNode<T> left) {
        this.left = left;
    }

    public BSTNode<T> getRight() {
        return right;
    }

    public void setRight(BSTNode<T> right) {
        this.right = right;
    }
}
/**
 * BST树的实现
 * @param <T>
 */
class BST<T extends Comparable<T>>{
    private BSTNode<T> root; // 指向BST树的根节点
    public BST() {
        this.root = null;
    }
 }

BST树常见代码题

BST树插入,删除,查询操作,递归和非递归实现

BST树的插入操作,递归和非递归代码实现:

/**
 * BST树的递归插入函数接口
 * @param val
 */
public void insert(T val){
    this.root = insert(root, val);
}

/**
 * BST树的递归插入具体实现函数
 * @param root
 * @param val
 * @return
 */
private BSTNode<T> insert(BSTNode<T> root, T val) {
    if(null == root){
        return new BSTNode<>(val);
    }

    if(root.getData().compareTo(val) > 0){
        root.setLeft(insert(root.getLeft(), val));
    } else if(root.getData().compareTo(val) < 0){
        root.setRight(insert(root.getRight(), val));
    } else {
        ;
    }

    return root;
}
/**
 * 非递归实现BST树的插入操作
 * @param val
 */
public void noncur_insert(T val){
    if(null == this.root){
        this.root = new BSTNode<T>(val);
        return;
    }
    BSTNode<T> parent = null;
    BSTNode<T> cur = this.root;
    while(cur != null){
        parent = cur;
        if(cur.getData().compareTo(val) > 0){
            cur = cur.getLeft();
        } else if(cur.getData().compareTo(val) < 0){
            cur = cur.getRight();
        } else{
            return;
        }
    }

    if(parent.getData().compareTo(val) > 0){
        parent.setLeft(new BSTNode<T>(val));
    } else{
        parent.setRight(new BSTNode<T>(val));
    }
}

BST树的删除操作,递归和非递归代码实现:

/**
 * 递归删除val元素的函数接口
 * @param val
 */
public void remove(T val){
    this.root = remove(root, val);
}

/**
 * 递归实现BST删除函数
 * @param root
 * @param val
 * @return
 */
private BSTNode<T> remove(BSTNode<T> root, T val) {
    if(root == null){
        return null;
    }

    if(root.getData().compareTo(val) > 0){
        root.setLeft(remove(root.getLeft(), val));
    } else if(root.getData().compareTo(val) < 0){
        root.setRight(remove(root.getRight(), val));
    } else {
        if(root.getLeft() != null
                && root.getRight() != null){
            BSTNode<T> pre = root.getLeft();
            while(pre.getRight() != null){
                pre = pre.getRight();
            }
            root.setData(pre.getData());
            root.setLeft(remove(root.getLeft(), pre.getData()));
        } else if(root.getLeft() != null){
            return root.getLeft();
        } else if(root.getRight() != null) {
            return root.getRight();
        } else {
            return null;
        }
    }
    return root;
}
/**
 * BST树的非递归删除
 * @param val
 */
public void noncur_remove(T val){
    BSTNode<T> parent = null;
    BSTNode<T> cur = root;

    while(null != cur){
        if(cur.getData().compareTo(val) > 0){
            parent = cur;
            cur = cur.getLeft();
        } else if(cur.getData().compareTo(val) < 0){
            parent = cur;
            cur = cur.getRight();
        } else {
            break;
        }
    }

    if(null == cur){
        return;
    }

    if(null != cur.getLeft() && null != cur.getRight()){
        // 用前驱结点代替删除节点,然后删除前驱结点
        BSTNode<T> old = cur;
        parent = cur;
        cur = cur.getLeft();
        while(null != cur.getRight()){
            parent = cur;
            cur = cur.getRight();
        }
        old.setData(cur.getData());
    }

    // 删除cur节点
    BSTNode<T> child = cur.getLeft();
    if(null == child){
        child = cur.getRight();
    }

    if(null == parent){
        this.root = child;
    } else if(parent.getLeft() == cur){
        parent.setLeft(child);
    } else {
        parent.setRight(child);
    }
}

BST树的查询操作,递归和非递归代码实现:

/**
 * 非递归查询元素val
 * @param val
 * @return
 */
public BSTNode<T> noncur_query(T val){
    BSTNode<T> cur = root;
    while(cur != null){
        if(cur.getData().compareTo(val) > 0){
            cur = cur.getLeft();
        } else if(cur.getData().compareTo(val) < 0){
            cur = cur.getRight();
        } else {
            return cur;
        }
    }
    return null;
}
/**
 * 递归查找元素val
 * @return
 */
public BSTNode<T> query(T val){
    return query(root, val);
}

private BSTNode<T> query(BSTNode<T> root, T val) {
    if(root == null)
        return null;

    if(root.getData().compareTo(val) > 0){
        return query(root.getLeft(), val);
    } else if(root.getData().compareTo(val) < 0){
        return query(root.getRight(), val);
    } else {
        return root;
    }
}

BST树前序,中序,后序,层序遍历的递归和非递归实现

BST前序遍历:

/**
 * BST树的前序遍历 VLR
 */
public void preOrder(){
    preOrder(root);
    System.out.println();
}

private void preOrder(BSTNode<T> root) {
    if(null != root){
        System.out.print(root.getData() + " ");
        preOrder(root.getLeft());
        preOrder(root.getRight());
    }
}

/**
 * 非递归实现前序遍历 VLR
 */
public void nonrecur_preOrder(){
    if(this.root == null){
        return;
    }

    LinkedList<BSTNode<T>> stack = new LinkedList<>();
    BSTNode<T> top = this.root;
    stack.push(top);

    while(!stack.isEmpty()){
        top = stack.pop();
        System.out.print(top.getData() + " ");

        if(top.getRight() != null){
            stack.push(top.getRight());
        }

        if(top.getLeft() != null){
            stack.push(top.getLeft());
        }
    }
    System.out.println();
}

BST中序遍历:

/**
 * BST树中序遍历 LVR
 */
public void inOrder(){
    inOrder(root);
    System.out.println();
}

private void inOrder(BSTNode<T> root) {
    if(null != root){
        inOrder(root.getLeft());
        System.out.print(root.getData() + " ");
        inOrder(root.getRight());
    }
}

/**
 * 中序遍历非递归实现
 */
public void nonrecur_inOrder(){
    if(this.root == null){
        return;
    }

    LinkedList<BSTNode<T>> stack = new LinkedList<>();
    BSTNode<T> top = this.root;

    while(!stack.isEmpty() || top != null){
        if(top != null){
            stack.push(top);
            top = top.getLeft();
        } else {
            top = stack.pop();
            System.out.print(top.getData() + " ");
            top = top.getRight();
        }
    }
    System.out.println();
}

BST后序遍历:

/**
 * BST树后序遍历 LRV
 */
public void lastOrder(){
    lastOrder(root);
    System.out.println();
}

private void lastOrder(BSTNode<T> root) {
    if(null != root){
        lastOrder(root.getLeft());
        lastOrder(root.getRight());
        System.out.print(root.getData() + " ");
    }
}

/**
 * 非递归实现后序遍历 LRV
 */
public void nonrecur_lastOrder(){
    if(this.root == null){
        return;
    }

    LinkedList<BSTNode<T>> stack = new LinkedList<>();
    LinkedList<BSTNode<T>> stack2 = new LinkedList<>();
    BSTNode<T> top = this.root;
    stack.push(top);

    while(!stack.isEmpty()){
        top = stack.pop();
        stack2.push(top);

        if(top.getLeft() != null){
            stack.push(top.getLeft());
        }

        if(top.getRight() != null){
            stack.push(top.getRight());
        }
    }

    while(!stack2.isEmpty()){
        System.out.print(stack2.pop().getData() + " ");
    }

    System.out.println();
}

BST层序遍历:

/**
 * 递归实现层序遍历
 */
public void levelOrder(){
    int height = level();
    for (int i = 0; i < height; i++) {
        levelOrder(root, i);
    }
    System.out.println();
}

private void levelOrder(BSTNode<T> root, int k) {
    if(root == null){
        return;
    }

    if(k == 0){
        System.out.print(root.getData() + " ");
    } else {
        levelOrder(root.getLeft(), k-1);
        levelOrder(root.getRight(), k-1);
    }
}

/**
 * 非递归实现层序遍历
 */
public void nonrecur_levelOrder(){
    if(this.root == null){
        return;
    }

    LinkedList<BSTNode<T>> queue = new LinkedList<>();
    BSTNode<T> cur = null;
    queue.offer(this.root);

    while(!queue.isEmpty()){
        cur = queue.poll();
        System.out.print(cur.getData() + " ");
        if(cur.getLeft() != null){
            queue.offer(cur.getLeft());
        }

        if(cur.getRight() != null){
            queue.offer(cur.getRight());
        }
    }

    System.out.println();
}

BST求树的高度,节点元素个数

BST树的高度:

/**
 * 递归求BST树的高度的函数接口
 * @return
 */
public int level(){
    return level(root);
}

/**
 * 返回BST树的高度
 * @param root
 * @return
 */
private int level(BSTNode<T> root) {
    if(root == null)
        return 0;
    int left = level(root.getLeft());
    int right = level(root.getRight());
    return (left > right ? left : right) + 1;
}

BST树求节点个数:

/**
 * 返回BST树节点的个数的函数接口
 * @return
 */
public int number(){
    return number(root);
}

/**
 * 求BST树节点个数的具体实现函数
 * @param root
 * @return
 */
private int number(BSTNode<T> root) {
    if(root == null){
        return 0;
    }

    return 1 + number(root.getLeft()) + number(root.getRight());
}

BST树区间元素查找

面试题,在BST树中,查找满足某一个区间元素范围的值,代码实现:

/**
     * 把BST树中满足[begin, end]区间的元素打印出来
     * @param begin
     * @param end
     */
    public void findAreaDatas(T begin, T end){
        findAreaDatas(this.root, begin, end);
        System.out.println();
    }

    private void findAreaDatas(BSTNode<T> root, T begin, T end) {
        if(root == null){
            return;
        }

        if(root.getData().compareTo(begin) > 0){ // 优化二叉树遍历
            findAreaDatas(root.getLeft(), begin, end);
        }

        if(root.getData().compareTo(begin) >= 0
            && root.getData().compareTo(end) <= 0){
            System.out.print(root.getData() + " ");
        }

        if(root.getData().compareTo(end) < 0){ // 优化二叉树遍历
            findAreaDatas(root.getRight(), begin, end);
        }
    }

判断二叉树是否是一颗BST树

/**
 * 判断一颗二叉树是否是BST树
 * @return
 */
BSTNode<T> pre = null; // pre保存中序遍历前一个节点的值
public boolean isBSTree(){
    return isBSTree(this.root);
}

/**
 * @param root
 * @return
 */
private boolean isBSTree(BSTNode<T> root) {
    if(root == null){
        return true;
    }

    if(!isBSTree(root.getLeft())){
        return false;
    }

    if(pre != null && root.getData().compareTo(pre.getData()) < 0){
        return false;
    }
    pre = root;

    return isBSTree(root.getRight());
}

BST求子树问题

/**
 * 判断childTree是否是当前BST的子树
 * @param childTree
 * @return
 */
public boolean isChildTree(BST<T> childTree){
    BSTNode<T> cur = query(childTree.root.getData());
    if(cur != null){
        return isChildTree(cur, childTree.root);
    }
    return false;
}

private boolean isChildTree(BSTNode<T> father, BSTNode<T> child) {
    if(father == null && child == null){
        return true;
    }
    if(father == null){
        return false;
    }
    if(child == null){
        return true;
    }
    if(father.getData().compareTo(child.getData()) != 0){
        return false;
    }

    return isChildTree(father.getLeft(), child.getLeft())
            && isChildTree(father.getRight(), child.getRight());

}

BST的LCA问题:求寻找最近公共祖先节点

/**
 * 获取BST树中两个节点的最近公共祖先
 * @param a
 * @param b
 * @return
 */
public T getLCA(T a, T b){
    return getLCA(root, a, b);
}

private T getLCA(BSTNode<T> root, T a, T b) {
    if(root == null){
        return null;
    }
    if(root.getData().compareTo(a) > 0
            && root.getData().compareTo(b) > 0){
        return getLCA(root.getLeft(), a, b);
    } else if(root.getData().compareTo(a) < 0
            && root.getData().compareTo(b) < 0){
        return getLCA(root.getRight(), a, b);
    } else {
        return root.getData();
    }
}

BST树的镜像反转问题

/**
 * BST树镜像翻转问题
 */
public void mirror(){
    mirror(root);
}

private void mirror(BSTNode<T> root) {
    if(root == null){
        return;
    }

    BSTNode<T> left = root.getLeft();
    root.setLeft(root.getRight());
    root.setRight(left);

    mirror(root.getLeft());
    mirror(root.getRight());
}

已知BST树的前序遍历和中序遍历,重建BST树

/**
 * 已知前序遍历和中序遍历,如何重建BST树
 * @param pre
 * @param in
 */
public void rebuild(T[] pre, T[] in){
    this.root = rebuild(pre, in, 0, pre.length-1, 0, in.length-1);
}

private BSTNode<T> rebuild(T[] pre, T[] in, int i, int j, int m, int n) {
    if(i > j || m > n)
        return null;

    BSTNode<T> node = new BSTNode<>(pre[i]);
    for(int k=m; k<=n; ++k) {
        if(pre[i].compareTo(in[k]) == 0){
            node.setLeft(rebuild(pre, in, i+1, i+(k-m), m, k-1));
            node.setRight(rebuild(pre, in, i+(k-m)+1, j, k+1, n));
            return node;
        }
    }
    return node;
}

判断一颗BST树是否是平衡树

平衡树的概念是,树中每个节点的左右子树高度差不超过1,因此可以对BST树进行递归,在递归回溯的时候,从叶子节点向上逐渐回溯到根节点,判断每一层是否有节点失衡,代码如下:

/**
 * 判断一个BST树是否是AVL树
 * @return 是AVL树返回true,否则返回false
 */
public boolean isAVLTree(){
    int l = isAVLTree(this.root);
    return l != -1;
}

private int isAVLTree(BSTNode<T> root) {
    if(root == null){
        return 0;
    } else {
        int left = isAVLTree(root.getLeft());
        int right = isAVLTree(root.getRight());
        // 上面两行是BST树的递归遍历调用,下面代码在递归回溯的时候判断节点是否失衡
        if(left == -1 || right == -1
            ||Math.abs(left-right) > 1){
            return -1;
        }
        return left > right ? left+1 : right+1;
    }
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值