AgumentBST---MaxMinBinarySearchTree

MaxMinBinarySearchTree中的每个节点会存储以他为根结点的子树的最大值最小值,这样可以使得之前介绍的findMax,findMin操作时间复杂度降为O(1)

MaxMinNode 节点结构如下

/**
 * BST树的优势在于我们可以在节点存放一些信息使得一些操作更高效
 * 比如在MaxMinNode中我们可以存放当前节点子树,包括自己的最大值最小值
 * 这样可以将findMax/findMin操作的时间复杂度优化到O(1)
 * @author haofan.whf
 * @version $Id: AugmentNode.java, v 0.1 2018年12月11日 下午7:30 haofan.whf Exp $
 */
public class MaxMinNode extends Node{

    private int minValue;

    private int maxValue;

    @Override
    public String toString() {
        return "Node{" +
                (this.getLeft() == null ? "" : "left=" + this.getLeft().getValue()) +
                (this.getRight() == null ? "" : ",right=" + this.getRight().getValue()) +
                (this.getParent() == null ? "" : ",parent=" + this.getParent().getValue()) +
                ", value=" + this.getValue() +
                (this.getList().size() == 0 ? "" : ",list=" + this.getList()) +
                ", minValue=" + this.getMinValue() +
                ", maxValue=" + this.getMaxValue() +
                '}';
    }
}

MaxMinBinarySearchTree覆写了BinarySearchTree一些修改树结构的方法,在insert/delete node的时候去更新需要更新的min/max值

/**
 * 需要对原始BST的修改
 * @author haofan.whf
 * @version $Id: MaxMinBinarySearchTree.java, v 0.1 2018年12月11日 下午7:55 haofan.whf Exp $
 */
public class MaxMinBinarySearchTree extends BinarySearchTree{

    /**
     * 查询最大值
     * T(N) = O(1)
     * @param root
     * @return
     */
    @Override
    public int findMax(Node root){
        return parseNode(root).getMaxValue();
    }

    /**
     * 查询最小值
     * T(N) = O(1)
     * @param root
     * @return
     */
    @Override
    public int findMin(Node root){
        return parseNode(root).getMinValue();
    }

    @Override
    public Node createNode(){
        return new MaxMinNode();
    }

    @Override
    public void doAfterInsert(Node n){
        MaxMinNode mmn = parseNode(n);
        //重新计算max/min
        //新增肯定是叶子结点
        mmn.setMaxValue(mmn.getValue());
        mmn.setMinValue(mmn.getValue());
        updateMaxMin(n, 1);
    }

    /**
     * 分几种情况
     * 1.无父节点,无需更新
     * 2.被删除的节点只有左子树,并且他是父节点的右节点 需要更新父节点的max
     * 3.被删除的节点只有左子树,并且他是父节点的左节点 无需更新
     * 4.被删除的节点只有右子树,并且他是父节点的左节点 需要更新父节点的min
     * 5.被删除的节点只有右子树,并且他是父节点的右节点 无需更新
     * 6.被删除的节点有左和右子树 这种情况不存在(会在delete操作前被swap掉)
     * 7.被删除的节点是叶子节点 更新父节点max or min
     * @param n
     */
    @Override
    public void doBeforeDelete(Node n){
        int leftOrRight = leftOrRight(n);
        if(leftOrRight == 0){
            //没有父节点,无需更新
            return;
        }
        if(n.getLeft() != null && n.getRight() == null && leftOrRight == -1){
            //被删除的节点只有左子树,并且他是父节点的左节点 无需更新
            return;
        }
        if(n.getLeft() == null && n.getRight() != null && leftOrRight == 1){
            //被删除的节点只有右子树,并且他是父节点的右节点 无需更新
            return;
        }
        if(n.getLeft() != null && n.getRight() != null){
            //被删除的节点有左和右子树 这种情况不存在(会在delete操作前被swap掉)
            throw new RuntimeException("impossible");
        }
        MaxMinNode mmnp = parseNode(n.getParent());

        if(n.getLeft() != null && n.getRight() == null && leftOrRight == 1){
            //被删除的节点只有左子树,并且他是父节点的右节点 需要更新父节点的max
            mmnp.setMaxValue(super.findMax(n.getLeft()));
        }
        if(n.getLeft() == null && n.getRight() != null && leftOrRight == -1){
            //被删除的节点只有右子树,并且他是父节点的左节点 需要更新父节点的min
            mmnp.setMinValue(super.findMin(n.getRight()));
        }
        if(n.getLeft() == null && n.getRight() == null){
            if(leftOrRight == 1){
                mmnp.setMaxValue(mmnp.getValue());
            }else{
                mmnp.setMinValue(mmnp.getValue());
            }
        }
        //之后将父节点当作新插入的节点更新即可
        updateMaxMin(n.getParent(), 0);
    }

    /**
     * 更新该节点所有父节点的max or min值
     * @param n
     */
    private void updateMaxMin(Node n, int opt){
        int leftOrRight = leftOrRight(n);
        if(leftOrRight == 0){
            //没有父节点,那么当前节点是根节点,是第一个被插入的元素
            return;
        }
        //当前节点的leftOrRight值
        int currentNodeLOR = leftOrRight;
        //currentNodeLOR * leftOrRight>0则同方向,反之则是zig-zag
        while (n != null && n.getParent() != null && currentNodeLOR * leftOrRight > 0){
            MaxMinNode mmn = parseNode(n);
            MaxMinNode mmnp = parseNode(n.getParent());
            if(leftOrRight == -1){
                //应当更新父节点的最小值
                if(opt==1 && mmn.getMinValue() < mmnp.getMinValue()){
                    mmnp.setMinValue(mmn.getMinValue());
                }else if(opt == 0 && mmn.getMinValue() > mmnp.getMinValue()){
                    mmnp.setMinValue(mmn.getMinValue());
                }
            }else if(leftOrRight == 1){
                //应当更新父节点的最大值
                if(opt == 1 && mmn.getMaxValue() > mmnp.getMaxValue()){
                    mmnp.setMaxValue(mmn.getMaxValue());
                }else if(opt == 0 && mmn.getMaxValue() < mmnp.getMaxValue()){
                    mmnp.setMaxValue(mmn.getMaxValue());
                }
            }
            currentNodeLOR = leftOrRight(n.getParent());
            n = n.getParent();
        }
    }

    /**
     * throw runtime exception unless node is MaxMinNode
     */
    private MaxMinNode parseNode(Node n){
        if(n instanceof MaxMinNode){
            return (MaxMinNode)n;
        }else{
            throw new RuntimeException("node type not match");
        }
    }

    /**
     * 对MaxMinBST结构进行修改后调用此方法查看结构的完整性
     * T(N) = O(N)
     * 需要遍历每个节点与他左右自节点的大小关系是否满足并且节点中记录的max/min值符合要求
     * @param root
     */
    public void checkRI(Node root){
        if(root == null){
            return;
        }
        int maxValue = super.findMax(root);
        int minValue = super.findMin(root);
        MaxMinNode mmn = parseNode(root);
        if(maxValue != mmn.getMaxValue() || minValue != mmn.getMinValue()){
            throw new RuntimeException("it's not a max/min bst");
        }
        if(root.getRight() != null){
            if(root.getValue() > root.getRight().getValue()){
                System.err.println(root);
                throw new RuntimeException("it's not a bst");
            }
        }
        if(root.getLeft() != null){
            if(root.getValue() < root.getLeft().getValue()){
                System.err.println(root);
                throw new RuntimeException("it's not a bst");
            }
        }
        checkRI(root.getRight());
        checkRI(root.getLeft());

    }
}

测试用例

public class BSTTest {
    @Test
    public void bstMaxMinAugment(){
        BinarySearchTree bst = new MaxMinBinarySearchTree();

        int[] insertArray = randomArray(1000);
        //insertArray = new int[]{2,5,3,9,6,1,8,4};
        Node root = new MaxMinNode();
        for (int i = 0; i < insertArray.length; i++) {
            bst.insert(root, insertArray[i]);
            bst.checkRI(root);
        }

        int[] deleteArray = randomArray(100);
        //deleteArray = new int[]{3,7,0,4,8};
        for (int i = 0; i < deleteArray.length; i++) {
            bst.delete(root, deleteArray[i]);
            bst.checkRI(root);
        }

    }

    private static int[] randomArray(int size){
        Random random = new Random();
        int[] array = new int[size];
        for (int i = 0; i < size; i++) {
            array[i] = random.nextInt(size);
        }
        return array;
    }


}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • B树的定义 一棵m阶的B树满足下列条件: 树中每个结点至多有m个孩子。 除根结点和叶子结点外,其它每个结点至少有m...
    文档随手记阅读 13,761评论 0 25
  • 0.目录 1.优先队列ADT 2.几种实现 3.二叉堆 4.d-堆 5.左式堆 6.斜堆 7.二项队列 8.斐波那...
    王侦阅读 3,471评论 1 2
  • 课程介绍 先修课:概率统计,程序设计实习,集合论与图论 后续课:算法分析与设计,编译原理,操作系统,数据库概论,人...
    ShellyWhen阅读 2,525评论 0 3
  • 一起吃三餐的时候,你的欢笑,我的错愕,虽然不在一张桌子上。 一起上班的时候,你的表情,我的目光,虽然有点距离。 偶...
    陈家仁阅读 228评论 0 1
  • 曾经 我宁可负这天下,负这满天神佛 也不愿负你 而你 却愿屈于神佛,想要这天下万物 弃我于水火炼狱 如今 我已成魔...
    哲学喵酱阅读 254评论 0 0

友情链接更多精彩内容