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

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


一.什么是二叉查找树?

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

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

如图所示。
[数据结构与算法]-二叉查找树(BLT)介绍及其实现(Java)_第1张图片

二.二叉查找树的作用

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

通常情况下,对于查找操作操作,保证操作在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插入到树中。
  8. remove(T t):将t元素删除。这里重点说一下删除操作。
    a)如果被删除的节点是一个树叶(即没有子节点的节点),则它可以立即被删除。
    b)如果被删除是节点有一个左节点或者右节点,则可以让该节点的父节点直接指向该节点的子节点。如图所示,删除节点50。
    [数据结构与算法]-二叉查找树(BLT)介绍及其实现(Java)_第2张图片
    c)麻烦的是删除同时有两个子节点的节点。一般的方式是:用被删除的节点的右子树中最小的节点的值来代替被删除节点的值,并且删除那个最小的节点。因为右子树中最小的节点不可能有做儿子,所以第二次remove只可能是a)或者b)中的情况,所以要容易的多。如图所示,删除节点200。
    [数据结构与算法]-二叉查找树(BLT)介绍及其实现(Java)_第3张图片
    PS:有关remove()的方法,我改进了《数据结构与算法分析(第3 版) 工业出版社》中的方法。对于c)所说的情况,只进行了一次遍历查找最小值并删除(树中是遍历两次)。思路在注解中有写。

四.实现代码

BinarySearchTree.java

/**
 * Created with IDEA
 * Author: MaYuzhe
 * Date: 2018/6/17
 * Time: 15:11
 * 

* BinarySearchTree 二叉查找树 */ public class BinarySearchTree> { private static class BinaryNode { BinaryNode(T t) { this(t, null, null); } BinaryNode(T t, BinaryNode left, BinaryNode right) { this.element = t; this.left = left; this.right = right; } T element; BinaryNode left; BinaryNode right; } private BinaryNode 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 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 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 findMin(BinaryNode node) { if (node == null) { return null; } else if (node.left == null) { return node; } return findMin(node.left); } /** * 寻找最大节点(递归) * * @param node * @return */ private BinaryNode findMax(BinaryNode node) { if (node == null) { return null; } else if (node.right == null) { return node; } return findMax(node.right); } // /** // * 寻找最小节点(非递归) // * @param node // * @return // */ // private BinaryNode findMin(BinaryNode node) { // if(node != null) { // while (node.left != null) { // node = node.left; // } // } // return node; // } // /** // * 寻找最大节点(非递归) // * @param node // * @return // */ // private BinaryNode findMax(BinaryNode node) { // if (node != null) { // while (node.right != null) { // node = node.right; // } // } // return node; // } /** * 插入操作 * * @param t * @param node * @return */ private BinaryNode insert(T t, BinaryNode 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 remove(T t, BinaryNode 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 removeRightMin(BinaryNode node, BinaryNode 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 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,喜欢的朋友可以支持一下。
data-structures-and-algorithm-study-notes-java


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

  • 二叉树的好处(应用)
  • 《数据结果与算法分析(第3版) 机械工业出版社》

你可能感兴趣的:(二叉查找树,BLT,数据结构,二叉树,数据结构与算法,一起学习数据结构与算法)