[数据结构与算法]-二叉查找树(BLT)介绍及其实现(Java)

版权声明:本文为博主原创文章,转载时请注明出处,谢谢!喝酒不骑马 邮箱[email protected] https://blog.csdn.net/Colton_Null/article/details/80722122

本文欢迎转载,转载前请联系作者,经允许后方可转载。转载后请注明出处,谢谢! http://blog.csdn.net/colton_null 作者:喝酒不骑马 Colton_Null from CSDN


一.什么是二叉查找树?

二叉查找树(Binary Search Tree, BST)是二叉树的一种。

简单来说,二叉查找树的特有性质是:对于树中的每个节点N,它的左子树中所有的元素值小于N中的值,所有右子树中的所有的元素值大于N中的值。

如图所示。
这里写图片描述

二.二叉查找树的作用

二叉排序树在数组和链表结构之间,对数据存储的一种折中方案。及能保证一定的插入删除效率,又保证了数据查找的效率。

通常情况下,对于查找操作操作,保证操作在O(logN)时间。这就是完成了哈希表不便完成的工作,动态性。但是二叉树有可能出现worst-case——最坏的情况,即如果输入序列已经排序,则时间复杂度为O(N)。

三.实现二叉查找树
1. BinaryNode类:为内部静态类(嵌套类),用于描述节点信息。节点中的元素对象,必须要实现Comparable接口,因为元素必须能比较出大小,即要通过compareTo()方法进行值的大小比较。
2. makeEmpty():使树置空,直接将根节点置空即可。
3. isEmpty():判断树是否为空,判断根节点是否为空即可。
4. contains(T t):查看t元素是否在树中。
5. findMin():查找最小值。沿着根遍历只查左节点,直到某个节点的左节点为空,则该节点的值为最小值。方法有两种,递归和非递归法。
6. findMax():查找最大值。思路痛findMin()。
7. insert(T t):将元素t插入到树中。
9. remove(T t):将t元素删除。这里重点说一下删除操作。
a)如果被删除的节点是一个树叶(即没有子节点的节点),则它可以立即被删除。
b)如果被删除是节点有一个左节点或者右节点,则可以让该节点的父节点直接指向该节点的子节点。如图所示,删除节点50。
这里写图片描述
c)麻烦的是删除同时有两个子节点的节点。一般的方式是:用被删除的节点的右子树中最小的节点的值来代替被删除节点的值,并且删除那个最小的节点。因为右子树中最小的节点不可能有做儿子,所以第二次remove只可能是a)或者b)中的情况,所以要容易的多。如图所示,删除节点200。
这里写图片描述
PS:有关remove()的方法,我改进了《数据结构与算法分析(第3 版) 工业出版社》中的方法。对于c)所说的情况,只进行了一次遍历查找最小值并删除(树中是遍历两次)。思路在注解中有写。

四.实现代码

BinarySearchTree.java

/**
 * Created with IDEA
 * Author: MaYuzhe
 * Date: 2018/6/17
 * Time: 15:11
 * <p>
 * BinarySearchTree 二叉查找树
 */
public class BinarySearchTree<T extends Comparable<? super T>> {

    private static class BinaryNode<T> {

        BinaryNode(T t) {
            this(t, null, null);
        }

        BinaryNode(T t, BinaryNode<T> left, BinaryNode<T> right) {
            this.element = t;
            this.left = left;
            this.right = right;
        }

        T element;
        BinaryNode<T> left;
        BinaryNode<T> right;
    }

    private BinaryNode<T> root;

    public BinarySearchTree() {
        this.root = null;
    }

    /**
     * 将树清空
     */
    public void makeEmpty() {
        this.root = null;
    }

    /**
     * 判断是否为空
     *
     * @return 为空则返回true,否则返回false
     */
    public boolean isEmpty() {
        return this.root == null;
    }

    public boolean contais(T t) {
        return contains(t, root);
    }

    public T findMin() {
        if (isEmpty()) {
            return null;
        }
        return findMin(root).element;
    }

    public T findMax() {
        if (isEmpty()) {
            return null;
        }
        return findMax(root).element;
    }

    public void insert(T t) {
        root = insert(t, root);
    }

    public void remove(T t) {
        root = remove(t, root);
    }

    public void printTree() {
        if (isEmpty()) {
            System.out.println("空树/Empty tree");
        } else {
            printTree(root);
        }
        System.out.println();
    }


    /**
     * 中序遍历方式打印树
     *
     * @param node
     */
    private void printTree(BinaryNode<T> node) {
        if (node != null) {
            printTree(node.left);
            System.out.println(node.element);
            printTree(node.right);
        }
    }


    /**
     * 判断被判断的元素在节点哪侧,递归判断。
     *
     * @param t    被判断的元素
     * @param node 当前节点
     * @return 如果有相等的值则返回true。否则返回false
     */
    private boolean contains(T t, BinaryNode<T> node) {
        if (node == null) {
            return false;
        }
        int compareResult = t.compareTo(node.element);

        if (compareResult < 0) {
            return contains(t, node.left);
        } else if (compareResult > 0) {
            return contains(t, node.right);
        } else {
            return true;
        }
    }

    /**
     * 寻找最小节点(递归)
     *
     * @param node
     * @return
     */
    private BinaryNode<T> findMin(BinaryNode<T> node) {
        if (node == null) {
            return null;
        } else if (node.left == null) {
            return node;
        }
        return findMin(node.left);
    }

    /**
     * 寻找最大节点(递归)
     *
     * @param node
     * @return
     */
    private BinaryNode<T> findMax(BinaryNode<T> node) {
        if (node == null) {
            return null;
        } else if (node.right == null) {
            return node;
        }
        return findMax(node.right);
    }

//    /**
//     * 寻找最小节点(非递归)
//     * @param node
//     * @return
//     */
//    private BinaryNode<T> findMin(BinaryNode<T> node) {
//        if(node != null) {
//            while (node.left != null) {
//                node = node.left;
//            }
//        }
//        return node;
//    }

//    /**
//     * 寻找最大节点(非递归)
//     * @param node
//     * @return
//     */
//    private BinaryNode<T> findMax(BinaryNode<T> node) {
//        if (node != null) {
//            while (node.right != null) {
//                node = node.right;
//            }
//        }
//        return node;
//    }

    /**
     * 插入操作
     *
     * @param t
     * @param node
     * @return
     */
    private BinaryNode<T> insert(T t, BinaryNode<T> node) {
        if (node == null) {
            return new BinaryNode<>(t, null, null);
        }

        int compareResult = t.compareTo(node.element);
        if (compareResult < 0) {
            node.left = insert(t, node.left);
        } else if (compareResult > 0) {
            node.right = insert(t, node.right);
        }
        return node;
    }

    /**
     * 删除节点
     *
     * @param t
     * @param node
     * @return
     */
    private BinaryNode<T> remove(T t, BinaryNode<T> node) {
        if (t == null) {
            return null;
        }
        int compareResult = t.compareTo(node.element);

        if (compareResult < 0) {
            node.left = remove(t, node.left);
        } else if (compareResult > 0) {
            node.right = remove(t, node.right);
        } else if (node.left != null && node.right != null) {
//            node.element = findMin(node.right).element;
//            node.right = remove(node.element, node.right);
            // 用removeRightMin方法替代上面两个操作,将两次遍历合并成一次遍历完成,提高效率
            node.right = removeRightMin(node, node.right);
        } else {
            node = node.left != null ? node.left : node.right;
        }
        return node;
    }

    /**
     * 删除右侧做小节点
     *
     * @param node
     * @param rNode
     * @return
     */
    private BinaryNode<T> removeRightMin(BinaryNode<T> node, BinaryNode<T> rNode) {
        if (rNode.left != null) {
            rNode.left = removeRightMin(node, rNode.left);
        } else {
            node.element = rNode.element;
            rNode = rNode.right;
        }
        return rNode;
    }
}

测试类
BinarySearchTreeTest.java

/**
 * Created with IDEA
 * Author: MaYuzhe
 * Date: 2018/6/17
 * Time: 15:42
 *
 * BinarySearchTreeTest 二叉查找树测试类
 */
public class BinarySearchTreeTest {
    public static void main(String[] args) {
        BinarySearchTree<Integer> binarySearchTree = new BinarySearchTree<>();
        // 测试insert,并用中序遍历打印树
        binarySearchTree.insert(10);
        binarySearchTree.insert(5);
        binarySearchTree.insert(1);
        binarySearchTree.insert(3);
        binarySearchTree.insert(8);
        binarySearchTree.insert(6);
        binarySearchTree.insert(9);
        binarySearchTree.insert(7);
        binarySearchTree.insert(17);
        binarySearchTree.insert(16);
        binarySearchTree.insert(18);
        binarySearchTree.printTree();

        // 测试remove
        binarySearchTree.remove(5);
        binarySearchTree.printTree();

        // 测试isEmpty方法
        System.out.println("树是否为空:" + binarySearchTree.isEmpty());

        // 测试contains
        System.out.println("树是否包含16:" + binarySearchTree.contais(16));
        System.out.println("树是否包含100:" + binarySearchTree.contais(100));

        // 测试findMin、findMax
        System.out.println("树的最小数据为:" + binarySearchTree.findMin());
        System.out.println("树的最大数据为:" + binarySearchTree.findMax());

        // 测试makeEmpty
        binarySearchTree.makeEmpty();
        System.out.println("树是否为空:" + binarySearchTree.isEmpty());
    }
}

输出

1
3
5
6
7
8
9
10
16
17
18

1
3
6
7
8
9
10
16
17
18

树是否为空:false
树是否包含16:true
树是否包含100:false
树的最小数据为:1
树的最大数据为:18
树是否为空:true

所有功能均正常。

以上就是有关二叉树的介绍及其部分功能的Java实现。


有关[数据结构与算法]的学习内容已经上传到github,喜欢的朋友可以支持一下。
https://github.com/MaYuzhe/data-structures-and-algorithm-study-notes-java


站在前人的肩膀上前行,感谢以下博客及文献的支持。

猜你喜欢

转载自blog.csdn.net/Colton_Null/article/details/80722122