數據結構--查詢三(b+樹)

BTree.javajava

package btree;

/**
 * description:
 *
 * @author: dawn.he QQ:       905845006
 * @email: dawn.he@cloudwise.com
 * @email: 905845006@qq.com
 * @date: 2019/12/12    12:03 AM
 */
import java.util.ArrayDeque;
import java.util.LinkedList;
import java.util.Queue;

/**
 * @author Herry
 *
 * @param <K>
 * @param <V>
 */
public class BTree<K extends Comparable<K>, V> {

    private BTNode<K, V> mRoot = null;
    private long mSize = 0l;

    /**
     * @return
     */
    public BTNode<K, V> getRootNode() {
        return mRoot;
    }

    /**
     * @return
     */
    public long size() {
        return mSize;
    }

    /**
     *
     */
    public void clear() {
        mSize = 0l;
        mRoot = null;
    }

    /**
     * @return
     */
    private BTNode<K, V> createNode() {
        BTNode<K, V> btNode = new BTNode<>();
        btNode.mIsLeaf = true;
        btNode.mCurrentKeyNum = 0;
        return btNode;
    }

    /**
     * @param key
     */
    private void checkKey(K key) {
        if (key == null) {
            throw new IllegalArgumentException();
        }
    }

    /**
     * 查找指定鍵所對應的值
     *
     * @param key
     * @return 若鍵存在,則返回鍵所對應的值。若鍵不存在,則拋出異常。
     */
    public V search(K key) {

        checkKey(key);

        BTNode<K, V> currentNode = mRoot;

        // 迭代查找每個可能存儲key的結點
        while (currentNode != null) {
            int possibleIdx = binarySearch(mRoot, key);
            BTKeyValue<K, V> possibleKeyValue = currentNode.mKeys[possibleIdx];
            // 判斷二分查找返回位置索引處的元素是否爲查找的元素,如果則返回其值,如不是,則迭代到下一個可能的結點中查找
            if (possibleIdx < currentNode.mCurrentKeyNum && key.compareTo(possibleKeyValue.mKey) == 0) {
                return possibleKeyValue.mValue;
            } else {
                currentNode = currentNode.mChildren[possibleIdx];
            }
        }
        return null;
    }

    /**
     * 用二分查找法查找結點中鍵的位置,若找到返回鍵的位置,若沒找到,則返回鍵應該插入的位置
     *
     * @param btNode
     * @param key
     * @return
     */
    private int binarySearch(BTNode<K, V> btNode, K key) {
        BTKeyValue<K, V>[] keys = btNode.mKeys;
        int lo = 0;
        int hi = btNode.mCurrentKeyNum - 1;
        while (lo <= hi) {
            int mid = (hi - lo) / 2 + lo;
            int cmp = key.compareTo(keys[mid].mKey);
            if (cmp == 0) {
                return mid;
            } else if (cmp > 0) {
                lo = mid + 1;
            } else if (cmp < 0) {
                hi = mid - 1;
            }
        }
        return lo;
    }

    /**
     * 將鍵-值對插入到BTree結構中
     *
     * @param key   鍵不容許爲null
     * @param value
     */
    public void insert(K key, V value) {

        checkKey(key);

        if (mRoot == null) {
            mRoot = createNode();
        }
        // 使用遞歸的方法將鍵-值對插入到BTree結構中
        mRoot = insert(mRoot, key, value);

    }

    /**
     * 遞歸插入方法
     *
     * @param x     要插入到的結點
     * @param key
     * @param value
     * @return
     */
    private BTNode<K, V> insert(BTNode<K, V> x, K key, V value) {

        // 1.首先判斷此節點是否已經爲滿,若滿,則將此節點分裂
        if (x.mCurrentKeyNum == BTNode.UPPER_BOUND_KEYNUM) {
            x = split(x);
        }
        // 2.對沒有滿的結點進行鍵值對的查找,找出可能的鍵值對索引,和可能的鍵值對
        int possibleIdx = binarySearch(x, key);
        /*
         * 因爲第一步操做會肯定當前節點爲非滿結點,故不用擔憂數組越界問題(否則試想,當此結點已滿,且要插入的鍵大於此節點中全部鍵,
         * 故possibleIdx的值會等於UPPER_BOUND_KEYNUM,故形成越界)
         */
        BTKeyValue<K, V> possibleKeyValue = x.mKeys[possibleIdx];
        /*
         * 3.判斷可能的鍵值對中的鍵是否與要插入的鍵相同(當要插入的鍵大於當前結點中全部的鍵時,possibleKeyValue取值爲x.mKeys[x.
         * mCurrentKeyNum]爲null,故要判斷possibleKeyValue的值是否爲空,以防止空指針異常)
         * 若是相同則直接替換當前值爲插入值,並返回當前結點(用於更新)
         */
        if (possibleKeyValue != null && key.compareTo(possibleKeyValue.mKey) == 0) {
            possibleKeyValue.mValue = value;
            return x;
        }
        /*
         * 4.當前節點爲葉子節點時,直接插入(因爲在最前邊進行了當前結點是否爲滿的判斷,並作了相應的處理,故到此步插入鍵值對後,此節點最多爲滿,且不會溢出)
         * 當前結點不爲葉子結點時,遞歸到下一個可能的結點繼續尋找、插入
         */
        if (x.mIsLeaf) {
            // 4.1
            for (int i = x.mCurrentKeyNum; i > possibleIdx; i--) {
                x.mKeys[i] = x.mKeys[i - 1];
            }
            x.mKeys[possibleIdx] = new BTKeyValue<>(key, value);
            x.mCurrentKeyNum++;
            mSize++;
        } else {
            // 4.2
            BTNode<K, V> t = insert(x.mChildren[possibleIdx], key, value);
            /*
             * 4.3判斷當返回的結點中的鍵值對數量爲1時,說明返回的結點通過了分裂,故須要將其合併到當前節點中(同上理,合併後,當前結點最多爲滿)
             */
            if (t.mCurrentKeyNum == 1) {
                // 4.3.1移動當前節點中的鍵值對爲要合併的鍵值對騰出地方,並存入
                for (int i = x.mCurrentKeyNum; i > possibleIdx; i--) {
                    x.mKeys[i] = x.mKeys[i - 1];
                }
                x.mKeys[possibleIdx] = t.mKeys[0];
                // 4.3.2移動當前節點中的子結點爲要合併的子結點騰出地方,並存入
                for (int i = x.mCurrentKeyNum + 1; i > possibleIdx + 1; i--) {
                    x.mChildren[i] = x.mChildren[i - 1];
                }
                x.mChildren[possibleIdx] = t.mChildren[0];
                x.mChildren[possibleIdx + 1] = t.mChildren[1];
                // 4.3.3更新當前結點的鍵值對計數器
                x.mCurrentKeyNum++;
            }
        }
        return x;
    }

    /**
     * 將滿結點x分裂爲含有一個鍵值對的父結點和兩個子結點,並返回父結點的連接
     *
     * @param x
     * @return
     */
    private BTNode<K, V> split(BTNode<K, V> x) {
        int mid = x.mCurrentKeyNum / 2;

        BTNode<K, V> left = new BTNode<>();
        for (int i = 0; i < mid; i++) {
            left.mKeys[i] = x.mKeys[i];
            left.mChildren[i] = x.mChildren[i];
        }
        left.mChildren[mid] = x.mChildren[mid];
        left.mIsLeaf = x.mIsLeaf;
        left.mCurrentKeyNum = mid;

        BTNode<K, V> right = new BTNode<>();
        for (int i = mid + 1; i < x.mCurrentKeyNum; i++) {
            right.mKeys[i - mid - 1] = x.mKeys[i];
            right.mChildren[i - mid - 1] = x.mChildren[i];
        }
        right.mChildren[x.mCurrentKeyNum - mid - 1] = x.mChildren[x.mCurrentKeyNum];
        right.mIsLeaf = x.mIsLeaf;
        right.mCurrentKeyNum = x.mCurrentKeyNum - mid - 1;

        BTNode<K, V> top = new BTNode<>();
        top.mCurrentKeyNum = 1;
        top.mIsLeaf = false;
        top.mKeys[0] = x.mKeys[mid];
        top.mChildren[0] = left;
        top.mChildren[1] = right;
        return top;
    }

    /**
     * @return
     */
    public BTKeyValue<K, V> minKey() {
        return minKey(mRoot);
    }

    /**
     * @param x
     * @return
     */
    private BTKeyValue<K, V> minKey(BTNode<K, V> x) {
        if (x == null) {
            return null;
        }
        if (x.mChildren[0] != null) {
            return minKey(x.mChildren[0]);
        } else {
            return x.mKeys[0];
        }
    }

    /**
     * @return
     */
    public BTKeyValue<K, V> maxKey() {
        return maxKey(mRoot);
    }

    /**
     * @param x
     * @return
     */
    private BTKeyValue<K, V> maxKey(BTNode<K, V> x) {
        if (x == null) {
            return null;
        }
        if (x.mChildren[x.mCurrentKeyNum] != null) {
            return maxKey(x.mChildren[x.mCurrentKeyNum]);
        } else {
            return x.mKeys[x.mCurrentKeyNum - 1];
        }
    }

    /**
     *
     * @param key
     * @return
     */
    public V deleteKey(K key) {

        checkKey(key);

        V v = search(key);
        // 遞歸的刪除鍵key
        mRoot = deleteKey(mRoot, key);
        return v;
    }

    /**
     * @param x
     * @param key
     * @return
     */
    private BTNode<K, V> deleteKey(BTNode<K, V> x, K key) {

        // 1.獲取要刪除的鍵可能處在當前結點上的索引位置
        int possibleIdx = binarySearch(x, key);

        // 2.根據當前結點是否爲葉子結點分狀況討論
        if (x.mIsLeaf == true) {
            // 2.1當前結點爲葉子節點

            if (possibleIdx < x.mCurrentKeyNum && key.compareTo(x.mKeys[possibleIdx].mKey) == 0) {
                // 2.1.1判斷在當前結點上possible索引位置上的鍵是否與要刪除的鍵相等(前提是possible索引小於當前節點鍵的數量,負責會出現空指針異常)
                // 若是相等,則直接刪除此鍵,不然,此鍵不存在樹中,不作任何操做

                for (int i = possibleIdx; i < x.mCurrentKeyNum - 1; i++) {
                    x.mKeys[i] = x.mKeys[i + 1];
                }
                x.mKeys[x.mCurrentKeyNum - 1] = null;
                x.mCurrentKeyNum--;
                mSize--;
            }
        } else {
            // 2.2當前結點不爲子結點
            if (possibleIdx < x.mCurrentKeyNum && key.compareTo(x.mKeys[possibleIdx].mKey) == 0) {
                // 2.2.1判斷在當前結點上possible索引位置上的鍵是否與要刪除的鍵相等(前提是possible索引小於當前節點鍵的數量,負責會出現空指針異常)
                // 若是成立,用possible索引處的子結點的最大鍵替換要刪除的鍵

                // 1)記住possilbe索引處子結點的最大鍵
                BTKeyValue<K, V> keyNeedToSwim = maxKey(x.mChildren[possibleIdx]);

                // 2)將1)中記住的鍵刪除
                x = deleteKey(x, keyNeedToSwim.mKey);

                // 3)將key替換爲記住的鍵
                possibleIdx = binarySearch(x, key);
                x.mKeys[possibleIdx] = keyNeedToSwim;

            } else {
                // 2.2.2
                // 若是不成立,遞歸的在possible索引處子結點上刪除鍵key

                // 遞歸刪除
                BTNode<K, V> t = deleteKey(x.mChildren[possibleIdx], key);

                // 檢測刪除後返回結點的狀態,若是不知足鍵數量>=最低度數-1,則酌情旋轉或合併
                if (t.mCurrentKeyNum < BTNode.LOWER_BOUND_KEYNUM) {
                    // 不知足鍵數量>=最低度數-1

                    // 判斷返回結點的兄弟結點的情況,若兄弟結點的鍵數量>最低度數-1,則旋轉(向兄弟結點借鍵),若兄弟結點的鍵數量<=最低度數-1,則與兄弟結點合併
                    if (BTNode.hasLeftSiblingAtIndex(x, possibleIdx)) {
                        if (BTNode.getLeftSiblingAtIndex(x, possibleIdx).mCurrentKeyNum > BTNode.LOWER_BOUND_KEYNUM) {
                            leftRotate(x, possibleIdx);
                        } else {
                            leftMerge(x, possibleIdx);
                        }
                    } else if (BTNode.hasRightSiblingAtIndex(x, possibleIdx)) {
                        if (BTNode.getRightSiblingAtIndex(x, possibleIdx).mCurrentKeyNum > BTNode.LOWER_BOUND_KEYNUM) {
                            rightRotate(x, possibleIdx);
                        } else {
                            rightMerge(x, possibleIdx);
                        }
                    }

                    // 判斷刪完後根節點是否沒有鍵存在,若沒有,則將根節點從新賦值
                    if (x == mRoot && x.mCurrentKeyNum == 0) {
                        x = x.mChildren[0];
                    }
                }
            }
        }
        return x;
    }

    /**
     * 合併父結點中位於possibleIdx和possibleIdx+1處的倆結點(因而可知可用執行作合併來完成右合併一樣的任務)
     *
     * @param x
     * @param possibleIdx
     * @return
     */
    private BTNode<K, V> rightMerge(BTNode<K, V> x, int possibleIdx) {
        return leftMerge(x, possibleIdx + 1);
    }

    /**
     * 合併父結點中位於possibleIdx和possibleIdx-1處的倆結點
     *
     * @param x
     * @param possibleIdx
     * @return
     */
    private BTNode<K, V> leftMerge(BTNode<K, V> x, int possibleIdx) {
        // 獲取左節點
        BTNode<K, V> leftNode = x.mChildren[possibleIdx - 1];
        // 獲取父結點要合併到左節點的鍵值對
        BTKeyValue<K, V> topKey = x.mKeys[possibleIdx - 1];
        // 獲取須要合併的結點
        BTNode<K, V> possibleNode = x.mChildren[possibleIdx];
        // 將父結點獲取的鍵值對放入左節點
        leftNode.mKeys[leftNode.mCurrentKeyNum] = topKey;
        // 將須要合併的結點的鍵值對所有放入左節點
        for (int i = 0; i < possibleNode.mCurrentKeyNum; i++) {
            leftNode.mKeys[i + leftNode.mCurrentKeyNum + 1] = possibleNode.mKeys[i];
        }
        // 同理,將結點連接也移過來
        for (int i = 0; i < possibleNode.mCurrentKeyNum + 1; i++) {
            leftNode.mChildren[i + leftNode.mCurrentKeyNum + 1] = possibleNode.mChildren[i];
        }
        // 更新左節點的鍵值對計數器
        leftNode.mCurrentKeyNum += 1 + possibleNode.mCurrentKeyNum;
        // 更新父結點
        for (int i = possibleIdx; i < x.mCurrentKeyNum; i++) {
            x.mKeys[i - 1] = x.mKeys[i];
        }
        x.mKeys[x.mCurrentKeyNum - 1] = null;
        for (int i = possibleIdx; i < x.mCurrentKeyNum; i++) {
            x.mChildren[i] = x.mChildren[i + 1];
        }
        x.mChildren[x.mCurrentKeyNum] = null;
        x.mCurrentKeyNum--;
//		System.out.println("leftMerge executed");
        return x;
    }

    /**
     * 從右結點借一個鍵值對過來
     *
     * @param x
     * @param possibleIdx
     * @return
     */
    private BTNode<K, V> rightRotate(BTNode<K, V> x, int possibleIdx) {

        // 獲取右節點和右節點中最小的鍵值對
        BTNode<K, V> rightNode = x.mChildren[possibleIdx + 1];
        BTKeyValue<K, V> rightKey = rightNode.mKeys[0];
        // 獲取右節點中最小的結點
        BTNode<K, V> rightFirstNode = rightNode.mChildren[0];
        // 獲取父結點交換位置的鍵值對
        BTKeyValue<K, V> topKey = x.mKeys[possibleIdx];
        // 獲取需補齊鍵值對的節點,並將父結點交換位置的鍵值對加到此節點的最高位
        BTNode<K, V> possibleNode = x.mChildren[possibleIdx];
        possibleNode.mKeys[possibleNode.mCurrentKeyNum] = topKey;
        // 將右節點中最小的結點添加到此節點
        possibleNode.mChildren[possibleNode.mCurrentKeyNum + 1] = rightFirstNode;
        possibleNode.mCurrentKeyNum++;

        // 將父結點拿走鍵值對的位置填上右節點提出的鍵值對
        x.mKeys[possibleIdx] = rightKey;
        // 將右節點提出的鍵值對和最小結點在右節點中刪除
        for (int i = 1; i < rightNode.mCurrentKeyNum; i++) {
            rightNode.mKeys[i - 1] = rightNode.mKeys[i];
        }
        rightNode.mKeys[rightNode.mCurrentKeyNum - 1] = null;
        for (int i = 1; i < rightNode.mCurrentKeyNum + 1; i++) {
            rightNode.mChildren[i - 1] = rightNode.mChildren[i];
        }
        rightNode.mChildren[rightNode.mCurrentKeyNum] = null;
        rightNode.mCurrentKeyNum--;
//		System.out.println("rightRotate executed");
        return x;
    }

    /**
     * ‘
     *
     * @param x           父結點
     * @param possibleIdx 須要補充鍵值對的子結點的索引
     * @return
     */
    private BTNode<K, V> leftRotate(BTNode<K, V> x, int possibleIdx) {

        // 獲取左節點和左節點中最大的鍵值對
        BTNode<K, V> leftNode = x.mChildren[possibleIdx - 1];
        BTKeyValue<K, V> leftKey = leftNode.mKeys[leftNode.mCurrentKeyNum - 1];
        // 獲取左節點中最大的結點
        BTNode<K, V> leftLastNode = leftNode.mChildren[leftNode.mCurrentKeyNum];
        // 獲取父結點交換位置的鍵值對
        BTKeyValue<K, V> topKey = x.mKeys[possibleIdx - 1];
        // 獲取需補齊鍵值對的節點,並移動其中的鍵值對將最低位空出來:以用來填充從父結點交換過來的鍵值對
        BTNode<K, V> possibleNode = x.mChildren[possibleIdx];
        for (int i = possibleNode.mCurrentKeyNum; i > 0; i--) {
            possibleNode.mKeys[i] = possibleNode.mKeys[i - 1];
        }
        // 同理對此節點的子結點
        for (int i = possibleNode.mCurrentKeyNum + 1; i > 0; i--) {
            possibleNode.mChildren[i] = possibleNode.mChildren[i - 1];
        }
        // 填充鍵值對和其帶過來的連接,並將鍵數量計數器加1
        possibleNode.mKeys[0] = topKey;
        possibleNode.mChildren[0] = leftLastNode;
        possibleNode.mCurrentKeyNum++;
        // 將父結點拿走鍵值對的位置填上左節點提出的鍵值對
        x.mKeys[possibleIdx - 1] = leftKey;
        // 將左節點提出的鍵值對和子結點在左節點中刪除
        leftNode.mKeys[leftNode.mCurrentKeyNum - 1] = null;
        leftNode.mChildren[leftNode.mCurrentKeyNum] = null;
        leftNode.mCurrentKeyNum--;
//		System.out.println("leftRotate executed");
        return x;
    }

    public static void main(String[] args) {
        BTree<Integer, String> bt = new BTree<>();
        for (int i = 1; i <= 56; i++) {
            bt.insert(i, "");
        }
        System.out.println("insert completed");
        System.out.println("size before delete:" + bt.size());
        bt.deleteKey(27);
        bt.deleteKey(42);
        System.out.println("size after delete:" + bt.size());
        Queue<BTNode<Integer, String>> queue = new ArrayDeque<>();

        ((ArrayDeque<BTNode<Integer,String>>) queue).offerLast(bt.getRootNode());
        while (!queue.isEmpty()) {
            BTNode<Integer, String> btn = queue.poll();
            for (int i = 0; i < btn.mCurrentKeyNum; i++) {

                System.out.print(btn.mKeys[i].mKey + " ");
            }
            System.out.println();
            if (!btn.mIsLeaf) {
                for (int i = 0; i <= btn.mCurrentKeyNum; i++) {
                    ((ArrayDeque<BTNode<Integer,String>>) queue).offerLast(btn.mChildren[i]);
                }
            }
        }



//        //add()和remove()方法在失敗的時候會拋出異常(不推薦)
//        Queue<String> queue = new ArrayDeque<String>();
//        //添加元素
//        queue.offer("a");
//        queue.offer("b");
//        queue.offer("c");
//        queue.offer("d");
//        queue.offer("e");
//        for(String q : queue){
//            System.out.println(q);
//        }
//        System.out.println("===");
//        System.out.println("poll="+queue.poll()); //返回第一個元素,並在隊列中刪除
//        for(String q : queue){
//            System.out.println(q);
//        }
//        System.out.println("===");
//        System.out.println("element="+queue.element()); //返回第一個元素
//        for(String q : queue){
//            System.out.println(q);
//        }
//        System.out.println("===");
//        System.out.println("peek="+queue.peek()); //返回第一個元素
//        for(String q : queue){
//            System.out.println(q);
//        }

    }
}

/**
 *
 *
 *
             *                                                                                                            |9|26|45|
             *                                                                                                          |p1|p2|p3|p4|
 *
 *                                                                                                                      |    |  |   |
 *
 *
 *                                                                                                            |           |     |        |
 *
 *
 *
 *                                                                                     |                         |              |                   |
 *
 *                                                                 |                                      |                     |                            |
 *
 *                                           |                                                    |                             |                                        |
 *
 *               |                                                                  |                                           |                                                       |
 *
 *            |3 | 6|                                                          |12|15|18|21|                                  |30|33|36|41|                                           |3 | 6|
 *           |p1|p2|p3|                                                       |p1|p2|p3|p4|p5|                              |p1|p2|p3|p4|p5|                                        |p1|p2|p3|
 *            |  |  |                                                           |  |  |  |  |                                 |  |  |  |  |                                           |  |  |
 *
 *
 *         |     |    |                                                    |     |   |   |  |                             |     |   |   |   |                                        |   |    |
 *
 *                                                                   |        |    |     |  |                          |       |
 *
 *     |         |      |                                       |       |        |     |     |                     |         |      |    |    |                                    |     |        |
 *
 *
 *   |           |        |                              |         |       |         |       |                 |           |         |      |        |                           |       |           |
 *
 *   |
 *  |            |          |                     |       |           |           |          |                |            |         |          |           |                    |      |               |
 *
 *  |             |          |             |          |            |          |              |               |            |          |            |            |              |         |                |
 *
 *|1 | 2|      |4 | 5|    |7 | 8|       |10|11|    |13|14|      |16|17|   |19|20|     |22|23|24|25|       |28|29|      |31|32|   |34|35|     |37|38|39|40|    |43|44|      |46|47|   |49|50|     |52|53|54|55|56|
 * ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////















 |p1|p2|p3|  |p1|p2|p3| |p1|p2|p3|    |p1|p2|p3| |p1|p2|p3|  |p1|p2|p3| |p1|p2|p3|  |p1|p2|p3|p4|p5|  |p1|p2|p3|  |p1|p2|p3| |p1|p2|p3|  |p1|p2|p3|p4|p5| |p1|p2|p3|  |p1|p2|p3| |p1|p2|p3|  |p1|p2|p3|p4|p5
 *
 * */

BTNode.java數組

package btree;

/**
 * description:
 *
 * @author: dawn.he QQ:       905845006
 * @email: dawn.he@cloudwise.com
 * @email: 905845006@qq.com
 * @date: 2019/12/12    12:04 AM
 */
public class BTNode<K extends Comparable<K>, V> {

    // 構成B樹的最小度數
    public final static int MIN_DEGREE = 3;
    // 除根節點外,每一個結點中總鍵數的下限
    public final static int LOWER_BOUND_KEYNUM = MIN_DEGREE - 1;
    // 包含根節點外,每一個結點中總鍵數的上限
    public final static int UPPER_BOUND_KEYNUM = (MIN_DEGREE * 2) - 1;

    protected boolean mIsLeaf;// 標記此節點是否爲葉子結點
    protected int mCurrentKeyNum;// 此節點的鍵數量計數器
    protected BTKeyValue<K, V>[] mKeys;// 用於存鍵值對的數組
    protected BTNode<K, V>[] mChildren;// 用於存子結點的數組

    /**
     * 構造函數
     */
    @SuppressWarnings("unchecked")
    public BTNode() {
        mIsLeaf = true;
        mCurrentKeyNum = 0;
        mKeys = new BTKeyValue[UPPER_BOUND_KEYNUM];
        mChildren = new BTNode[UPPER_BOUND_KEYNUM + 1];
    }

    protected static BTNode<?, ?> getChildNodeAtIndex(BTNode<?, ?> btNode, int keyIdx, int nDirection) {
        if (btNode.mIsLeaf) {
            return null;
        }
        keyIdx += nDirection;
        if ((keyIdx < 0) || (keyIdx > btNode.mCurrentKeyNum)) {
            throw new IllegalArgumentException();
        }

        return btNode.mChildren[keyIdx];
    }

    /**
     * 返回btNode節點中位於keyIdx位上的鍵左邊的子結點
     * @param btNode
     * @param keyIdx
     * @return
     */
    protected static BTNode<?, ?> getLeftChildAtIndex(BTNode<?, ?> btNode, int keyIdx) {
        return getChildNodeAtIndex(btNode, keyIdx, 0);
    }

    /**
     * 返回btNode節點中位於keyIdx位上的鍵右邊的子結點
     * @param btNode
     * @param keyIdx
     * @return
     */
    protected static BTNode<?, ?> getRightChildAtIndex(BTNode<?, ?> btNode, int keyIdx) {
        return getChildNodeAtIndex(btNode, keyIdx, 1);
    }

    /**
     * @param parentNode
     * @param keyIdx
     * @return 返回父結點的keyIdx位上的子結點的左兄弟結點
     */
    protected static BTNode<?, ?> getLeftSiblingAtIndex(BTNode<?, ?> parentNode, int keyIdx) {
        return getChildNodeAtIndex(parentNode, keyIdx, -1);
    }

    /**
     *
     * @param parentNode
     * @param keyIdx
     * @return	返回父結點的keyIdx位上的子結點的右兄弟結點
     */
    protected static BTNode<?, ?> getRightSiblingAtIndex(BTNode<?, ?> parentNode, int keyIdx) {
        return getChildNodeAtIndex(parentNode, keyIdx, 1);
    }


    /**
     * 判斷父結點的keyIdx位上的子結點是否存在左兄弟結點
     * @param parentNode
     * @param keyIdx
     * @return
     */
    protected static boolean hasLeftSiblingAtIndex(BTNode<?, ?> parentNode, int keyIdx) {
        if (keyIdx - 1 < 0) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 判斷父結點的keyIdx位上的子結點是否存在右兄弟結點
     * @param parentNode
     * @param keyIdx
     * @return
     */
    protected static boolean hasRightSiblingAtIndex(BTNode<?, ?> parentNode, int keyIdx) {
        if (keyIdx + 1 > parentNode.mCurrentKeyNum) {
            return false;
        } else {
            return true;
        }
    }
}

BTKeyValue.java函數

package btree;

/**
 * description:
 *
 * @author: dawn.he QQ:       905845006
 * @email: dawn.he@cloudwise.com
 * @email: 905845006@qq.com
 * @date: 2019/12/12    12:04 AM
 */
/**
 * @author Herry
 *
 * @param <K>
 * @param <V>
 */
public class BTKeyValue<K extends Comparable<K>, V> {

    protected K mKey;
    protected V mValue;

    public BTKeyValue(K mKey, V mValue) {
        super();
        this.mKey = mKey;
        this.mValue = mValue;
    }
}
相關文章
相關標籤/搜索