数据结构-b树

import java.util.Arrays;

/**
 * @author ddq
 */
@SuppressWarnings("all")
public class BTree {
    private class Node {
        private int[] keys;
        private int size;
        private Node[] children;

        private boolean isLeaf;

        private Node(int capacity) {
            keys = new int[capacity];
            children = new Node[capacity + 1];
        }

        private Node() {
            this(2);
        }

        @Override
        public String toString() {
            return Arrays.toString(Arrays.copyOf(keys, size));
        }
    }

    private Node root;

    //btree中最小的度
    private int minBranch;

    //btree每个节点允许最小的key数量
    private int minKeyThreshold;

    //btree每个节点允许最大的key数量
    private int maxKeyThreshold;

    private static enum MOVE_TYPE {
        MOVE_TO_LEFT, MOVE_TO_RIGHT;
    }

    public BTree(int minBranch) {
        this.minBranch = minBranch;
        this.minKeyThreshold = minBranch - 1;
        this.maxKeyThreshold = 2 * minBranch - 1;
        this.root = new Node(maxKeyThreshold);
        this.root.isLeaf = true;
    }

    public BTree() {
        this(2);
    }

    public boolean contains(int key) {
        return doContains(root, key);
    }

    private boolean doContains(Node node, int key) {
        int i = 0;
        while (i < node.size) {
            if (key == node.keys[i]) return true;
            if (key < node.keys[i]) break;
            i++;
        }
        if (node.isLeaf) return false;
        return doContains(node.children[i], key);
    }

    private void doPut(Node parent, Node node, int key, int index) {
        int i = 0;
        while (i < node.size) {
            if (key == node.keys[i]) return;
            if (key < node.keys[i]) break;
            i++;
        }
        //如果是叶子节点则直接添加
        if (node.isLeaf) addKey(node, key);
        else doPut(node, node.children[i], key, i);
        split(parent, node, index);
    }

    private void split(Node parent, Node node, int index) {
        if (node.size < maxKeyThreshold) return;
        //一会儿准备往父节点移动的数据
        int mid = node.keys[minBranch - 1];
        //原节点,为了更好的区分,故取别名left
        Node left = node;
        //新节点,为了更好的区分,故取别名right
        Node right = createNewNode(maxKeyThreshold, left.isLeaf);
        shareKeys(left, minBranch, right, 0, left.size - minBranch);
        shareChildren(left, minBranch, right, 0, minBranch);
        parent = checkParent(parent);
        addKey(parent, mid);
        addChild(parent, left, index);
        addChild(parent, right, index + 1);
    }

    private Node createNewNode(int capacity, boolean isLeaf) {
        Node node = new Node(capacity);
        node.isLeaf = isLeaf;
        return node;
    }

    private void addChild(Node parent, Node child, int index) {
        System.arraycopy(parent.children, index, parent.children, index + 1, parent.size - index);
        parent.children[index] = child;
    }

    private Node checkParent(Node parent) {
        if (parent != null) return parent;
        parent = new Node(maxKeyThreshold);
        this.root = parent;
        return parent;
    }

    private void addKey(Node node, int key) {
        int i = 0;
        while (i < node.size) {
            if (key == node.keys[i]) return;
            if (key < node.keys[i]) break;
            i++;
        }
        System.arraycopy(node.keys, i, node.keys, i + 1, node.size - i);
        node.keys[i] = key;
        node.size++;
    }

    private void shareKeys(Node src, int srcPos, Node dest, int destPos, int length) {
        System.arraycopy(src.keys, srcPos, dest.keys, destPos, length);
        dest.size = length;
        src.size = src.size - dest.size - 1;
    }

    private void shareChildren(Node src, int srcPos, Node dest, int destPos, int length) {
        if (src.isLeaf || dest.isLeaf) return;
        System.arraycopy(src.children, srcPos, dest.children, destPos, length);
    }

    public void put(int key) {
        doPut(null, root, key, 0);
    }

    public void remove(int key) {
        doRemove(null, root, key, 0);
    }

    private void doRemove(Node parent, Node node, int key, int index) {
        /**
         * 需要判断当前是否是叶子节点
         * 叶子节点,直接删除
         * 非叶子节点,将后续节点替换到当前节点,然后对后继节点进行递归删除
         * */
        int i = 0;
        if (node.isLeaf) {
            //叶子节点,直接删除
            while (i < node.size) {
                if (key < node.keys[i]) return;
                if (key == node.keys[i]) break;
                i++;
            }
            if (node.size <= i) return;
            removeKeyOfIndex(node, i);
            node.size--;
        } else {
            //非叶子节点,将后续节点替换到当前节点,然后对后继节点进行递归删除
            while (i < node.size) {
                if (key <= node.keys[i]) break;
                i++;
            }
            if (key == node.keys[i]) {
                Node tmp = node.children[i + 1];
                while (tmp.children[0] != null) tmp = tmp.children[0];
                node.keys[i] = tmp.keys[0];
                doRemove(node, node.children[i + 1], tmp.keys[0], i + 1);
            } else {
                doRemove(node, node.children[i], key, i);
            }
        }
        balance(parent, node, index);
    }

    //在对keys进行删减的时候可能会导致 keys数量
    private void balance(Node parent, Node node, int index) {
        if (node.size >= minKeyThreshold) return;
        if (parent == null) {
            this.root = node.children[0];
            return;
        }

        Node leftBrother = index >= 1 ? parent.children[index - 1] : null;
        Node rightBrother = index < parent.size ? parent.children[index + 1] : null;
        if (leftBrother != null && leftBrother.size > minKeyThreshold) {
            //将父节点最后一个key移除并将移除的返回值添加到node
            addKey(node, removeKeyOfIndex(parent, index - 1));
            parent.size--;
            //将左兄弟的最后一个key移除并将移除的返回值添加到parent
            addKey(parent, removeKeyOfIndex(leftBrother, leftBrother.size - 1));
            if (!node.isLeaf) addChild(node, removeChildOfIndex(leftBrother, leftBrother.size), 0);
            leftBrother.size--;

            return;
        }
        if (rightBrother != null && rightBrother.size > minKeyThreshold) {
            //将父节点最后一个key移除并将移除的返回值添加到node
            addKey(node, removeKeyOfIndex(parent, index));
            parent.size--;
            //将右兄弟的第一个key移除并将移除的返回值添加到parent
            addKey(parent, removeKeyOfIndex(rightBrother, 0));
            if (!node.isLeaf) addChild(node, removeChildOfIndex(rightBrother, 0), node.size);
            rightBrother.size--;
            return;
        }
        //如果左兄弟不为null则往左兄弟进行合并
        if (leftBrother != null) {
            //1.先将自己去除掉
            removeChildOfIndex(parent, index);
            //node实际上有效的孩子数为当前node的长度+1,当前的node也就是下一次递归的parent,实际上在下一次递归的时候,当前node的size就已经减1了故孩子数是  size+1 => 现size+1
            int validRightChildSize = node.isLeaf ? 0 : node.size + 1;
            //左兄弟实际上有效的孩子数
            int validLeftChildSize = leftBrother.isLeaf ? 0 : leftBrother.size + 1;
            //2.将父节点index-1位置的key给去除掉且将去除的返回值往左兄弟中添加
            addKey(leftBrother, removeKeyOfIndex(parent, index - 1));
            parent.size--;
            //3.将第1步得到的返回值(包括keys和children)往左兄弟进行合并
            moveToTarget(leftBrother, validLeftChildSize, node, validRightChildSize, MOVE_TYPE.MOVE_TO_LEFT);
            return;
        }
        //如果左兄弟为null则自己向右兄弟合并
        if (rightBrother != null) {
            //1.先将自己去除掉
            removeChildOfIndex(parent, index);
            //node实际上有效的孩子数为当前node的长度+1,当前的node也就是下一次递归的parent,实际上在下一次递归的时候,当前node的size就已经减1了故孩子数是  size+1 => 现size+1
            int validLeftChildSize = node.isLeaf ? 0 : node.size + 1;
            //右兄弟实际上有效的孩子数
            int validRightChildSize = rightBrother.isLeaf ? 0 : rightBrother.size + 1;
            //2.将父节点index-1位置的key给去除掉且将去除的返回值往左兄弟中添加
            addKey(rightBrother, removeKeyOfIndex(parent, index));
            parent.size--;
            moveToTarget(rightBrother, validRightChildSize, node, validLeftChildSize, MOVE_TYPE.MOVE_TO_RIGHT);
            return;
        }

    }

    //将keys和children往target进行合并
    private void moveToTarget(Node dest, int validDestChildSize, Node src, int validSrcChildSize, MOVE_TYPE moveType) {
        //首先进行keys的拷贝
        if (moveType == MOVE_TYPE.MOVE_TO_RIGHT) {
            System.arraycopy(dest.keys, 0, dest.keys, src.size, dest.size);
            System.arraycopy(src.keys, 0, dest.keys, 0, src.size);
            if (!src.isLeaf && !dest.isLeaf) {
                System.arraycopy(dest.children, 0, dest.children, validSrcChildSize, validDestChildSize);
                System.arraycopy(src.children, 0, dest.children, 0, validSrcChildSize);
            }
        } else {
            System.arraycopy(src.keys, 0, dest.keys, dest.size, src.size);
            if (!src.isLeaf && !dest.isLeaf) {
                System.arraycopy(src.children, 0, dest.children, validDestChildSize, validSrcChildSize);
            }
        }
        //如果有效的子节点数量为0,则将该dest置为叶子节点
        if (validDestChildSize + validSrcChildSize == 0) dest.isLeaf = true;
    }

    private Node removeChildOfIndex(Node node, int index) {
        Node removed = node.children[index];
        System.arraycopy(node.children, index + 1, node.children, index, node.size - index);
        node.children[node.size] = null;
        return removed;
    }

    //删除node指定下标的key
    private int removeKeyOfIndex(Node node, int index) {
        int removed = node.keys[index];
        System.arraycopy(node.keys, index + 1, node.keys, index, node.size - index - 1);
        return removed;
    }
}



你可能感兴趣的:(数据结构,b树,java)