Java数据结构----树--二叉查找(搜索或排序)树BST

二叉查找(搜索)树(Binary Search Tree)又称二叉排序树(Binary Sort Tree),是基于二叉树,BST具有下列性质:
1、若左子树不空,则其左子树上的所有结点的值均小于根结点的值;
2、若右子树不空,则其右子树上的所有结点的值均大于根结点的值;
3、左、右子树也分别为二叉查找树。

               

结点类

public class BinaryNode {
    Integer data;
    BinaryNode leftChild;
    BinaryNode rightChild;

    public BinaryNode() {
    }

    public BinaryNode(int data) {
        leftChild = null;
        rightChild = null;
        this.data = data;
    }

    public BinaryNode(Integer data, BinaryNode leftChild, BinaryNode rightChild) {
        this.data = data;
        this.leftChild = leftChild;
        this.rightChild = rightChild;
    }
}

二叉查找树实现类

public class BinarySearchTree {
    private BinaryNode root;
    List<BinaryNode> nodeList = new LinkedList<BinaryNode>();

    //相关方法 。。。。
}
1、插入操作

    /**
     * 非递归插入操作x的过程如下:
     * 1、若b是空树,则直接将插入的结点作为根结点插入。
     * 2、x等于b的根结点的数据的值,则直接返回,否则。
     * 3、若x小于b的根结点的数据的值,则将x要插入的结点的位置改变为b的左子树,否则。
     * 4、将x要出入的结点的位置改变为b的右子树。
     */
    public boolean insert(Integer value) {
        if (root == null) {
            root = new BinaryNode(value);   //新构造一个二叉查找树
            nodeList.add(root);

        } else {
            BinaryNode parent = null;
            BinaryNode current = root;

            while (current != null) {
                //compareTo就是比较两个值,如果前者大于后者,返回1,等于返回0,小于返回-1
                if (value.compareTo(current.data) == -1) {
                    parent = current;
                    current = current.leftChild;

                } else if (value.compareTo(current.data) == 1) {
                    parent = current;
                    current = current.rightChild;
                    
                } else
                    return false;
            }

            if (value.compareTo(parent.data) == -1)
                parent.leftChild = new BinaryNode(value);
            else
                parent.rightChild = new BinaryNode(value);

            nodeList.add(parent);
        }
        return true;
    }

递归插入:

    /**
     * 递归插入: 得到的nodeList的size不是插入数据的大小!!!
     */
    public BinaryNode recursiveInsert(Integer value) {
        return recursiveInsert(value, this.root);
    }

    private BinaryNode recursiveInsert(Integer value, BinaryNode node) {
        if (root == null)
            root = new BinaryNode(value);   //新构造一个二叉查找树

        if (node == null)  //如果是叶节点,则没有孩子
            return new BinaryNode(value, null, null);

        int result = value.compareTo(node.data);

        //value小于node.data返回-1
        if (result == -1) {
            node.leftChild = recursiveInsert(value, node.leftChild);

        } else if (result == 1) {
            node.rightChild = recursiveInsert(value, node.rightChild);
        }

        nodeList.add(node);
        return node;
    }
测试:

    @Test
    public void test() {
        BinarySearchTree tree = new BinarySearchTree();
        BinarySearchTree tree1 = new BinarySearchTree();
        int[] keys = new int[] { 8, 3, 10, 1, 6, 14, 4, 7, 13 };

        for (int key:keys){
            tree.insert(key);
            tree1.recursiveInsert(key);
        }

        List<BinaryNode> list = tree.getBinarySearchTree();
        List<BinaryNode> list1 = tree1.getBinarySearchTree();

        System.out.println("非递归插入节点后,树的大小:"+ list.size());
        System.out.println("递归插入节点后,树的大小:" + list1.size());
    }
非递归插入节点后,树的大小:9
递归插入节点后,树的大小:17
2、删除操作

对于二叉查找树的删除操作(这里根据值删除,而非结点)分三种情况:
不过在此之前,我们应该确保根据给定的值找到了要删除的结点,如若没找到该结点不会执行删除操作!这里暂时没有考虑
下面三种情况假设已经找到了要删除的结点。
1、如果结点为叶子结点(没有左、右子树),此时删除该结点不会玻化树的结构直接删除即可,并修改其父结点指向它的引用为null.如下图:

2、如果其结点只包含左子树,或者右子树的话,此时直接删除该结点,并将其左子树或者右子树设置为其父结点的左子树或者右子树即可,此操作不会破坏树结构。


 3、当结点的左右子树都不空的时候,一般的删除策略是用其右子树的最小数据(容易找到)代替要删除的结点数据并递归删除该结点(此时为null),因为右子树的最小结点不可能有左孩子,所以第二次删除较为容易。z的左子树和右子树均不空。找到z的后继y,因为y一定没有左子树,所以可以删除y,并让y的父亲节点成为y的右子树的父亲节点,并用y的值代替z的值.如图:

实现代码

    public void remove(Integer value) {
        this.root = remove(value,root);
    }

    /**
     * 递归删除:
     *
     * eg:添加的节点顺序为8,3,9.删除根结点,返回值则为3
     * @return 返回值始终是最新的根节点!!!
     */
    private BinaryNode remove(Integer value, BinaryNode node) {
        if (node == null)
            return null;

        int result = value.compareTo(node.data);

        //result<0:表示需要删除的节点在左子树
        if (result == -1) {
            node.leftChild = remove(value, node.leftChild);

        } else if (result == 1) {//在右子树
            node.rightChild = remove(value, node.rightChild);

        } else if (node.leftChild != null && node.rightChild != null) { //结点的左右子树都不时候
            //先找到需要删除的节点下,右子树中最小的节点并将它的值赋给需要删除的节点。
            node.data = findMin(node.rightChild).data;  //找出右子树最小值(因为右子树中的节点的值一定大于根节点)
            //删除前面找到的最小的节点
            node.rightChild = remove(node.data, node.rightChild);

        }else {
            //找到需要删除的节点且节点下有一个子节点(左或者右)
            node = (node.leftChild != null) ? node.leftChild : node.rightChild;
        }

        return node;
    }
3、查找

    /**
     * 在二叉查找树中查找x的过程如下:
     * 1、若二叉树是空树,则查找失败。
     * 2、若x等于根结点的数据,则查找成功,否则。
     * 3、若x小于根结点的数据,则递归查找其左子树,否则。
     * 4、递归查找其右子树。
     */
    public boolean find(Integer value) {
        return contains(value, this.root);
    }

    private boolean contains(Integer value, BinaryNode node) {
        if (node == null)
            return false;

        int result = value.compareTo(node.data); //-1,0,1
        if (result == -1) {
            return contains(value, node.leftChild); //递归查询左子树

        }else if (result == 1) {
            return contains(value, node.rightChild); //递归查询右子树

        } else {
            return true;
        }
    }
4、其它相关方法

    //获取二叉查找树
    public List<BinaryNode> getBinarySearchTree() {
        return nodeList;
    }

    /**
     * 找出最小的值
     * @return 返回最小值
     */
    public Integer findMin() {
        return findMin(root).data;
    }
    private BinaryNode findMin(BinaryNode node) {
        if (node == null)
            return null;
        else if (node.leftChild == null) //如果左孩子没有,只返回根结点
            return node;

        return findMin(node.leftChild);
    }

    /**
     * 找出最大的值
     */
    public Integer findMax() {
        return findMax(root).data;
    }
    private BinaryNode findMax(BinaryNode node) {
        if (node ==null)
            return null;
        else if (node.rightChild == null)
            return node;
        else
            return findMax(node.rightChild);
    }


    public void inOrderTraverse() {
        inOrderTraverse(root);
    }

    /**
     * 递归中序排序:
     * 二叉查找树中序排序后的二叉查找树是有序的
     */
    public void inOrderTraverse(BinaryNode node) {
        if (node != null) {
            inOrderTraverse(node.leftChild);
            System.out.print(node.data + " ");
            inOrderTraverse(node.rightChild);
        }
    }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
做一门精致,全面详细的 java数据结构与算法!!!让天下没有难学的数据结构,让天下没有难学的算法,不吹不黑,我们的讲师及其敬业,可以看到课程视频,课件,代码的录制撰写,都是在深夜,如此用心,其心可鉴,他不掉头发,谁掉头发???总之你知道的,不知道的,我们都讲,并且持续更新,走过路过,不要错过,不敢说是史上最全的课程,怕违反广告法,总而言之,言而总之,这门课你值得拥有,好吃不贵,对于你知识的渴求,我们管够管饱话不多说,牛不多吹,我们要讲的本门课程内容:稀疏数组、单向队列、环形队列、单向链表、双向链表、环形链表、约瑟夫问题、栈、前缀、缀、后缀表达式、缀表达式转换为后缀表达式、递归与回溯、迷宫问题、八皇后问题、算法的时间复杂度、冒泡排序、选择排序、插入排序、快速排序、归并排序、希尔排序、基数排序(桶排序)、堆排序排序速度分析、查找、插值查找、斐波那契查找、散列、哈希表、二叉树二叉树与数组转换、二叉排序(BST)、AVL、线索二叉树、赫夫曼、赫夫曼编码、多路查找(BB+和B*)、图、图的DFS算法和BFS、程序员常用10大算法、查找算法(非递归)、分治算法、动态规划算法、KMP算法、贪心算法、普里姆算法、克鲁斯卡尔算法、迪杰斯特拉算法、弗洛伊德算法马踏棋盘算法。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值