B+樹的算法(java實現)


  • 定義

  一顆m階B+樹滿足以下幾個條件:

  1.除根節點外的節點的關鍵字個數最大為m-1,最小為m/2

  2.除葉節點外的每個節點的孩子節點的數目為該節點關鍵字個數加一,這些孩子節點的的關鍵字的范圍與父節點關鍵字的大小對應(這個看圖才看的清楚)

  3.葉子節點存放着所有的關鍵字,葉子節點間按關鍵字的大小用指針相互連接。內部節點以葉子節點的關鍵字的最小值作為索引

  • B+樹的優勢

  B+樹相較於B樹最大的優勢在於數據全部都存在於葉子節點,葉子節點間以指針相互連接,這樣在進行按照索引的范圍查找的時候就只需要遍歷前后指針就可以完成,而B樹要一個一個索引去進行查找,效率差別很大。

  B+樹相較於hash的優勢在於B+樹不用一次將數據全部加載到內存,而是先確定要查詢索引的地址,將對應的地址的索引加載到內存。而hash需要將全部的數據一次性加載到內存才能完成查找。

  • B+樹代碼實現

  首先定義一個節點類

 1 import java.util.List;
 2 
 3 /*節點類*/
 4 public class Node {
 5 
 6     //節點的子節點
 7     private List<Node> nodes;
 8     //節點的鍵值對
 9     private List<KeyAndValue> keyAndValue;
10     //節點的后節點
11     private Node nextNode;
12     //節點的前節點
13     private Node previousNode;
14     //節點的父節點
15     private Node parantNode;
16 
17     public Node( List<Node> nodes, List<KeyAndValue> keyAndValue, Node nextNode,Node previousNode, Node parantNode) {
18         this.nodes = nodes;
19         this.keyAndValue = keyAndValue;
20         this.nextNode = nextNode;
21         this.parantNode = parantNode;
22         this.previousNode = previousNode;
23     }
24 
25      boolean isLeaf() {
26         return nodes==null;
27     }
28 
29      boolean isHead() {
30         return previousNode == null;
31     }
32 
33      boolean isTail() {
34         return nextNode == null;
35     }
36 
37      boolean isRoot() {
38         return parantNode == null;
39     }
40 
41 
42      List<Node> getNodes() {
43         return nodes;
44     }
45 
46      void setNodes(List<Node> nodes) {
47         this.nodes = nodes;
48     }
49 
50 
51     List<KeyAndValue> getKeyAndValue() {
52         return keyAndValue;
53     }
54 
55 //    public void setKeyAndValue(List<KeyAndValue> KeyAndValue) {
56 //        this.keyAndValue = KeyAndValue;
57 //    }
58 
59     Node getNextNode() {
60         return nextNode;
61     }
62 
63      void setNextNode(Node nextNode) {
64         this.nextNode = nextNode;
65     }
66 
67      Node getParantNode() {
68         return parantNode;
69     }
70 
71      void setParantNode(Node parantNode) {
72         this.parantNode = parantNode;
73     }
74 
75      Node getPreviousNode() {
76         return previousNode;
77     }
78 
79      void setPreviousNode(Node previousNode) {
80         this.previousNode = previousNode;
81     }
82 }

   定義一個存儲關鍵字和數據的類

 1 public class KeyAndValue implements Comparable<KeyAndValue>{
 2     /*存儲索引關鍵字*/
 3     private int key;
 4     /*存儲數據*/
 5     private Object value;
 6 
 7     @Override
 8     public int compareTo(KeyAndValue o) {
 9         //根據key的值升序排列
10         return this.key - o.key;
11     }
12 
13     public int getKey() {
14         return key;
15     }
16 
17     public void setKey(int key) {
18         this.key = key;
19     }
20 
21     public Object getValue() {
22         return value;
23     }
24 
25     public void setValue(Object value) {
26         this.value = value;
27     }
28 
29      KeyAndValue(int key, Object value) {
30         this.key = key;
31         this.value = value;
32     }
33 }

   最后是具體的實現代碼

  1 import java.util.*;
  2 
  3 
  4 public class Btree {
  5     private static final String NODE = "NODE";
  6     static final String INT = "INT";
  7     private static final String PRENODE = "PRENODE";
  8     private static final String NEXTNODE = "NEXTNODE";
  9     //B+樹的階數
 10     private int rank;
 11     //根節點
 12     private Node root;
 13     //頭結點
 14     private Node head;
 15 
 16     Btree(int rank) {
 17         this.rank = rank;
 18     }
 19 
 20     public Node getRoot() {
 21         return root;
 22     }
 23 
 24     public void insert(KeyAndValue entry) {
 25         List<KeyAndValue> keyAndValues1 = new ArrayList<>();
 26         //插入第一個節點
 27         if (head == null) {
 28             keyAndValues1.add(entry);
 29             head = new Node(null, keyAndValues1, null, null, null);
 30             root = new Node(null, keyAndValues1, null, null, null);
 31         } else {
 32             Node node = head;
 33             //遍歷鏈表,找到插入鍵值對對應的節點
 34             while (node != null) {
 35                 List<KeyAndValue> keyAndValues = node.getKeyAndValue();
 36                 int exitFlag = 0;
 37                 //如果插入的鍵的值和當前節點鍵值對集合中的某個鍵的值相等,則直接替換value
 38                 for (KeyAndValue KV : keyAndValues) {
 39                     if (KV.getKey() == entry.getKey()) {
 40                         KV.setValue(entry.getValue());
 41                         exitFlag = 1;
 42                         break;
 43                     }
 44                 }
 45                 //如果插入的鍵已經有了,則退出循環
 46                 if (exitFlag == 1) {
 47                     break;
 48                 }
 49                 //如果當前節點是最后一個節點或者要插入的鍵值對的鍵的值小於下一個節點的鍵的最小值,則直接插入當前節點
 50                 if (node.getNextNode() == null || node.getNextNode().getKeyAndValue().get(0).getKey() >= entry.getKey()) {
 51                     splidNode(node, entry);
 52                     break;
 53                 }
 54                 //移動指針
 55                 node = node.getNextNode();
 56             }
 57         }
 58     }
 59 
 60 
 61     //判斷是否需要拆分節點
 62     private void splidNode(Node node, KeyAndValue addkeyAndValue) {
 63         List<KeyAndValue> keyAndValues = node.getKeyAndValue();
 64 
 65         if (keyAndValues.size() == rank - 1) {
 66             //先插入待添加的節點
 67             keyAndValues.add(addkeyAndValue);
 68             Collections.sort(keyAndValues);
 69             //取出當前節點的鍵值對集合
 70             //取出原來的key-value集合中間位置的下標
 71             int mid = keyAndValues.size() / 2;
 72             //取出原來的key-value集合中間位置的鍵
 73             int midKey = keyAndValues.get(mid).getKey();
 74             //構造一個新的鍵值對,不是葉子節點的節點不存儲value的信息
 75             KeyAndValue midKeyAndValue = new KeyAndValue(midKey, "");
 76             //將中間位置左邊的鍵值對封裝成集合對象
 77             List<KeyAndValue> leftKeyAndValues = new ArrayList<>();
 78             for (int i = 0; i < mid; i++) {
 79                 leftKeyAndValues.add(keyAndValues.get(i));
 80             }
 81             //將中間位置右邊邊的鍵值對封裝成集合對象
 82             List<KeyAndValue> rightKeyAndValues = new ArrayList<>();
 83             //如果是葉子節點則在原節點中保留上移的key-value,否則原節點刪除上移的key-value
 84             int k;
 85             if (node.isLeaf()) {
 86                 k = mid;
 87             } else {
 88                 k = mid + 1;
 89             }
 90             for (int i = k; i < rank; i++) {
 91                 rightKeyAndValues.add(keyAndValues.get(i));
 92             }
 93             //對左右兩邊的元素重排序
 94             Collections.sort(leftKeyAndValues);
 95             Collections.sort(rightKeyAndValues);
 96             //以mid為界限將當前節點分列成兩個節點,維護前指針和后指針
 97             Node rightNode;
 98             Node leftNode;
 99 //            if (node.isLeaf()) {
100             //如果是葉子節點維護前后指針
101             rightNode = new Node(null, rightKeyAndValues, node.getNextNode(), null, node.getParantNode());
102             leftNode = new Node(null, leftKeyAndValues, rightNode, node.getPreviousNode(), node.getParantNode());
103             rightNode.setPreviousNode(leftNode);
104 //            } else {
105 //                //如果不是葉子不維護前后指針
106 //                rightNode = new Node(null, rightKeyAndValues, null, null, node.getParantNode());
107 //                leftNode = new Node(null, leftKeyAndValues, null, null, node.getParantNode());
108 //            }
109             //如果當前分裂的節點有孩子節點,設置分裂后節點和孩子節點的關系
110             if (node.getNodes() != null) {
111                 //取得所有地孩子節點
112                 List<Node> nodes = node.getNodes();
113                 List<Node> leftNodes = new ArrayList<>();
114                 List<Node> rightNodes = new ArrayList<>();
115                 for (Node childNode : nodes) {
116                     //取得當前孩子節點的最大鍵值
117                     int max = childNode.getKeyAndValue().get(childNode.getKeyAndValue().size() - 1).getKey();
118                     if (max < midKeyAndValue.getKey()) {
119                         //小於mid處的鍵的數是左節點的子節點
120                         leftNodes.add(childNode);
121                         childNode.setParantNode(leftNode);
122                     } else {
123                         //大於mid處的鍵的數是右節點的子節點
124                         rightNodes.add(childNode);
125                         childNode.setParantNode(rightNode);
126                     }
127                 }
128                 leftNode.setNodes(leftNodes);
129                 rightNode.setNodes(rightNodes);
130             }
131 
132             //當前節點的前節點
133             Node preNode = node.getPreviousNode();
134             //分裂節點后將分裂節點的前節點的后節點設置為左節點
135             if (preNode != null) {
136                 preNode.setNextNode(leftNode);
137             }
138 
139             //當前節點的后節點
140             Node nextNode = node.getNextNode();
141             //分裂節點后將分裂節點的后節點的前節點設置為右節點
142             if (nextNode != null) {
143                 nextNode.setPreviousNode(rightNode);
144             }
145 
146             //如果由頭結點分裂,則分裂后左邊的節點為頭節點
147             if (node == head) {
148                 head = leftNode;
149             }
150 
151             //父節點的子節點
152             List<Node> childNodes = new ArrayList<>();
153             childNodes.add(rightNode);
154             childNodes.add(leftNode);
155             //分裂
156             //當前節點無父節點
157             if (node.getParantNode() == null) {
158                 //父節點的鍵值對
159                 List<KeyAndValue> parentKeyAndValues = new ArrayList<>();
160                 parentKeyAndValues.add(midKeyAndValue);
161                 //構造父節點
162                 Node parentNode = new Node(childNodes, parentKeyAndValues, null, null, null);
163                 //將子節點與父節點關聯
164                 rightNode.setParantNode(parentNode);
165                 leftNode.setParantNode(parentNode);
166                 //當前節點為根節點
167                 root = parentNode;
168             } else {
169                 Node parentNode = node.getParantNode();
170                 //將原來的孩子節點(除了被拆分的節點)和新的孩子節點(左孩子和右孩子)合並之后與父節點關聯
171                 childNodes.addAll(parentNode.getNodes());
172                 //移除正在被拆分的節點
173                 childNodes.remove(node);
174                 //將子節點與父節點關聯
175                 parentNode.setNodes(childNodes);
176                 rightNode.setParantNode(parentNode);
177                 leftNode.setParantNode(parentNode);
178                 if (parentNode.getParantNode() == null) {
179                     root = parentNode;
180                 }
181                 //當前節點有父節點,遞歸調用拆分的方法,將父節點拆分
182                 splidNode(parentNode, midKeyAndValue);
183             }
184         } else {
185             keyAndValues.add(addkeyAndValue);
186             //排序
187             Collections.sort(keyAndValues);
188         }
189     }
190 
191 
192     //打印B+樹
193     void printBtree(Node root) {
194         if (root == this.root) {
195             //打印根節點內的元素
196             printNode(root);
197             System.out.println();
198         }
199         if (root == null) {
200             return;
201         }
202 
203         //打印子節點的元素
204         if (root.getNodes() != null) {
205             //找到最左邊的節點
206             Node leftNode = null;
207             Node tmpNode = null;
208             List<Node> childNodes = root.getNodes();
209             for (Node node : childNodes) {
210                 if (node.getPreviousNode() == null) {
211                     leftNode = node;
212                     tmpNode = node;
213                 }
214             }
215 
216             while (leftNode != null) {
217                 //從最左邊的節點向右打印
218                 printNode(leftNode);
219                 System.out.print("|");
220                 leftNode = leftNode.getNextNode();
221             }
222             System.out.println();
223             printBtree(tmpNode);
224         }
225     }
226 
227     //打印一個節點內的元素
228     private void printNode(Node node) {
229         List<KeyAndValue> keyAndValues = node.getKeyAndValue();
230         for (int i = 0; i < keyAndValues.size(); i++) {
231             if (i != (keyAndValues.size() - 1)) {
232                 System.out.print(keyAndValues.get(i).getKey() + ",");
233             } else {
234                 System.out.print(keyAndValues.get(i).getKey());
235             }
236         }
237     }
238 
239     public Object search(int key, Node node, String mode) {
240 
241         //如果是葉子節點則直接取值
242         if (node.isLeaf()) {
243             List<KeyAndValue> keyAndValues = node.getKeyAndValue();
244             for (KeyAndValue keyAndValue : keyAndValues) {
245                 if (keyAndValue.getKey() == key) {
246                     switch (mode) {
247                         case NODE:
248                             return node;
249                         case INT:
250                             return keyAndValue.getValue();
251                     }
252                 }
253             }
254             return null;
255         }
256 
257 
258         List<Node> nodes = node.getNodes();
259         //如果尋找的key小於節點的鍵的最小值
260         int minKey = node.getKeyAndValue().get(0).getKey();
261         if (key < minKey) {
262             for (Node n : nodes) {
263                 List<KeyAndValue> keyAndValues = n.getKeyAndValue();
264                 //找到子節點集合中最大鍵小於父節點最小鍵節點
265                 if (keyAndValues.get(keyAndValues.size() - 1).getKey() < minKey) {
266                     return search(key, n, mode);
267                 }
268             }
269         }
270         //如果尋找的key大於節點的鍵的最大值
271         int maxKey = getMaxKeyInNode(node);
272         if (key >= maxKey) {
273             for (Node n : nodes) {
274                 List<KeyAndValue> keyAndValues = n.getKeyAndValue();
275                 //找到子節點集合中最小鍵大於等於父節點最小大鍵節點
276                 if (keyAndValues.get(0).getKey() >= maxKey) {
277                     return search(key, n, mode);
278                 }
279             }
280         }
281 
282         //如果尋找的key在最大值和最小值之間,首先定位到最窄的區間
283         int min = getLeftBoundOfKey(node, key);
284         int max = getRightBoundOfKey(node, key);
285 
286 
287         //去所有的子節點中找鍵的范圍在min和max之間的節點
288         for (Node n : nodes) {
289             List<KeyAndValue> kvs = n.getKeyAndValue();
290             //找到子節點集合中鍵的范圍在min和max之間的節點
291             if (kvs.get(0).getKey() >= min && kvs.get(kvs.size() - 1).getKey() < max) {
292                 return search(key, n, mode);
293             }
294         }
295         return null;
296     }
297 
298 
299     public boolean delete(int key) {
300         System.out.println("delete:" + key);
301         System.out.println();
302 
303         //首先找到要刪除的key所在的節點
304         Node deleteNode = (Node) search(key, root, NODE);
305         //如果沒找到則刪除失敗
306         if (deleteNode == null) {
307             return false;
308         }
309 
310         if (deleteNode == root) {
311             delKeyAndValue(root.getKeyAndValue(), key);
312             return true;
313         }
314 
315         if (deleteNode == head && isNeedMerge(head)) {
316             head = head.getNextNode();
317         }
318 
319         return merge(deleteNode, key);
320     }
321 
322 
323     //平衡當前節點和前節點或者后節點的數量,使兩者的數量都滿足條件
324     private boolean balanceNode(Node node, Node bratherNode, String nodeType) {
325         if (bratherNode == null) {
326             return false;
327         }
328         List<KeyAndValue> delKeyAndValues = node.getKeyAndValue();
329         if (isMoreElement(bratherNode)) {
330             List<KeyAndValue> bratherKeyAndValues = bratherNode.getKeyAndValue();
331             int bratherSize = bratherKeyAndValues.size();
332             //兄弟節點刪除挪走的鍵值對
333             KeyAndValue keyAndValue = null;
334             KeyAndValue keyAndValue1;
335             switch (nodeType) {
336                 case PRENODE:
337                     keyAndValue = bratherKeyAndValues.remove(bratherSize - 1);
338                     keyAndValue1 = getKeyAndValueinMinAndMax(node.getParantNode(), keyAndValue.getKey(), getMinKeyInNode(node));
339                     keyAndValue1.setKey(keyAndValue.getKey());
340                     break;
341                 case NEXTNODE:
342                     keyAndValue = bratherKeyAndValues.remove(0);
343                     keyAndValue1 = getKeyAndValueinMinAndMax(node.getParantNode(), getMaxKeyInNode(node), keyAndValue.getKey());
344                     keyAndValue1.setKey(bratherKeyAndValues.get(0).getKey());
345                     break;
346             }
347             //當前節點添加從前一個節點得來的鍵值對
348             delKeyAndValues.add(keyAndValue);
349 
350             //對鍵值對重排序
351             Collections.sort(delKeyAndValues);
352             return true;
353         }
354         return false;
355     }
356 
357     public boolean merge(Node node, int key) {
358         List<KeyAndValue> delKeyAndValues = node.getKeyAndValue();
359         //首先刪除該key-vaule
360         delKeyAndValue(delKeyAndValues, key);
361         //如果要刪除的節點的鍵值對的數目小於節點最大鍵值對數目*填充因子
362         if (isNeedMerge(node)) {
363             Boolean isBalance;
364             //如果左節點有富余的鍵值對,則取一個到當前節點
365             Node preNode = getPreviousNode(node);
366             isBalance = balanceNode(node, preNode, PRENODE);
367             //如果此時已經平衡,則已經刪除成功
368             if (isBalance) return true;
369 
370             //如果右兄弟節點有富余的鍵值對,則取一個到當前節點
371             Node nextNode = getNextNode(node);
372             isBalance = balanceNode(node, nextNode, NEXTNODE);
373 
374             return isBalance || mergeNode(node, key);
375         } else {
376             return true;
377         }
378     }
379 
380     //合並節點
381     //key 待刪除的key
382     private boolean mergeNode(Node node, int key) {
383         if (node.isRoot()) {
384             return false;
385         }
386         Node preNode;
387         Node nextNode;
388         Node parentNode = node.getParantNode();
389         List<Node> childNodes = parentNode.getNodes();
390         List<Node> childNodes1 = node.getNodes();
391         List<KeyAndValue> parentKeyAndValue = parentNode.getKeyAndValue();
392         List<KeyAndValue> keyAndValues = node.getKeyAndValue();
393 
394         if (node.isLeaf()) {
395             if (parentKeyAndValue.size() == 1 && parentNode != root) {
396                 return true;
397             }
398             preNode = getPreviousNode(node);
399             nextNode = getNextNode(node);
400             if (preNode != null) {
401                 List<KeyAndValue> preKeyAndValues = preNode.getKeyAndValue();
402                 keyAndValues.addAll(preKeyAndValues);
403                 if (preNode.isHead()) {
404                     head = node;
405                     node.setPreviousNode(null);
406                 } else {
407                     preNode.getPreviousNode().setNextNode(node);
408                     node.setPreviousNode(preNode.getPreviousNode());
409                 }
410                 //將合並后節點的后節點設置為當前節點的后節點
411                 preNode.setNextNode(node.getNextNode());
412                 KeyAndValue keyAndValue = getKeyAndValueinMinAndMax(parentNode, getMinKeyInNode(preNode), key);
413                 delKeyAndValue(parentKeyAndValue, keyAndValue.getKey());
414                 if (parentKeyAndValue.isEmpty()) {
415                     root = node;
416                 } else {
417                     //刪除當前節點
418                     childNodes.remove(preNode);
419                 }
420                 Collections.sort(keyAndValues);
421                 merge(parentNode, key);
422                 return true;
423             }
424 
425             if (nextNode != null) {
426                 List<KeyAndValue> nextKeyAndValues = nextNode.getKeyAndValue();
427                 keyAndValues.addAll(nextKeyAndValues);
428                 if (nextNode.isTail()) {
429                     node.setPreviousNode(null);
430                 } else {
431                     nextNode.getNextNode().setPreviousNode(node);
432                     node.setNextNode(nextNode.getNextNode());
433                 }
434 
435                 KeyAndValue keyAndValue = getKeyAndValueinMinAndMax(parentNode, key, getMinKeyInNode(nextNode));
436                 delKeyAndValue(parentKeyAndValue, keyAndValue.getKey());
437                 if (parentKeyAndValue.isEmpty()) {
438                     root = node;
439                     node.setParantNode(null);
440                 } else {
441                     //刪除當前節點
442                     childNodes.remove(nextNode);
443                 }
444                 Collections.sort(keyAndValues);
445                 merge(parentNode, key);
446                 return true;
447             }
448             //前節點和后節點都等於null那么是root節點
449             return false;
450         } else {
451             preNode = getPreviousNode(node);
452             nextNode = getNextNode(node);
453             if (preNode != null) {
454                 //將前一個節點和當前節點還有父節點中的相應Key-value合並
455                 List<KeyAndValue> preKeyAndValues = preNode.getKeyAndValue();
456                 preKeyAndValues.addAll(keyAndValues);
457                 int min = getMaxKeyInNode(preNode);
458                 int max = getMinKeyInNode(node);
459                 //父節點中移除這個key-value
460                 KeyAndValue keyAndValue = getKeyAndValueinMinAndMax(parentNode, min, max);
461                 parentKeyAndValue.remove(keyAndValue);
462                 if (parentKeyAndValue.isEmpty()) {
463                     root = preNode;
464                     node.setParantNode(null);
465                     preNode.setParantNode(null);
466                 } else {
467                     childNodes.remove(node);
468                 }
469                 assert nextNode != null;
470                 preNode.setNextNode(nextNode.getNextNode());
471                 //前節點加上一個當前節點的所有子節點中最小key的key-value
472                 KeyAndValue minKeyAndValue = getMinKeyAndValueInChildNode(node);
473                 assert minKeyAndValue != null;
474                 KeyAndValue keyAndValue1 = new KeyAndValue(minKeyAndValue.getKey(), minKeyAndValue.getValue());
475                 preKeyAndValues.add(keyAndValue1);
476                 List<Node> preChildNodes = preNode.getNodes();
477                 preChildNodes.addAll(node.getNodes());
478                 //將當前節點的孩子節點的父節點設為當前節點的后節點
479                 for (Node node1 : childNodes1) {
480                     node1.setParantNode(preNode);
481                 }
482                 Collections.sort(preKeyAndValues);
483                 merge(parentNode, key);
484                 return true;
485             }
486 
487             if (nextNode != null) {
488                 //將后一個節點和當前節點還有父節點中的相應Key-value合並
489                 List<KeyAndValue> nextKeyAndValues = nextNode.getKeyAndValue();
490                 nextKeyAndValues.addAll(keyAndValues);
491 
492                 int min = getMaxKeyInNode(node);
493                 int max = getMinKeyInNode(nextNode);
494                 //父節點中移除這個key-value
495                 KeyAndValue keyAndValue = getKeyAndValueinMinAndMax(parentNode, min, max);
496                 parentKeyAndValue.remove(keyAndValue);
497                 childNodes.remove(node);
498                 if (parentKeyAndValue.isEmpty()) {
499                     root = nextNode;
500                     nextNode.setParantNode(null);
501                 } else {
502                     childNodes.remove(node);
503                 }
504                 nextNode.setPreviousNode(node.getPreviousNode());
505                 //后節點加上一個當后節點的所有子節點中最小key的key-value
506                 KeyAndValue minKeyAndValue = getMinKeyAndValueInChildNode(nextNode);
507                 assert minKeyAndValue != null;
508                 KeyAndValue keyAndValue1 = new KeyAndValue(minKeyAndValue.getKey(), minKeyAndValue.getValue());
509                 nextKeyAndValues.add(keyAndValue1);
510                 List<Node> nextChildNodes = nextNode.getNodes();
511                 nextChildNodes.addAll(node.getNodes());
512                 //將當前節點的孩子節點的父節點設為當前節點的后節點
513                 for (Node node1 : childNodes1) {
514                     node1.setParantNode(nextNode);
515                 }
516                 Collections.sort(nextKeyAndValues);
517                 merge(parentNode, key);
518                 return true;
519             }
520             return false;
521         }
522     }
523 
524     //得到當前節點的前節點
525     private Node getPreviousNode(Node node) {
526         if (node.isRoot()) {
527             return null;
528         }
529 
530         Node parentNode = node.getParantNode();
531         //得到兄弟節點
532         List<Node> nodes = parentNode.getNodes();
533         List<KeyAndValue> keyAndValues = new ArrayList<>();
534         for (Node n : nodes) {
535             List<KeyAndValue> list = n.getKeyAndValue();
536             int maxKeyAndValue = list.get(list.size() - 1).getKey();
537             if (maxKeyAndValue < getMinKeyInNode(node)) {
538                 keyAndValues.add(new KeyAndValue(maxKeyAndValue, n));
539             }
540         }
541         Collections.sort(keyAndValues);
542         if (keyAndValues.isEmpty()) {
543             return null;
544         }
545         return (Node) keyAndValues.get(keyAndValues.size() - 1).getValue();
546     }
547 
548 
549     //得到當前節點的后節點
550     private Node getNextNode(Node node) {
551         if (node.isRoot()) {
552             return null;
553         }
554 
555         Node parentNode = node.getParantNode();
556         //得到兄弟節點
557         List<Node> nodes = parentNode.getNodes();
558         List<KeyAndValue> keyAndValues = new ArrayList<>();
559         for (Node n : nodes) {
560             List<KeyAndValue> list = n.getKeyAndValue();
561             int minKeyAndValue = list.get(0).getKey();
562             if (minKeyAndValue > getMaxKeyInNode(node)) {
563                 keyAndValues.add(new KeyAndValue(minKeyAndValue, n));
564             }
565         }
566         Collections.sort(keyAndValues);
567         if (keyAndValues.isEmpty()) {
568             return null;
569         }
570         return (Node) keyAndValues.get(0).getValue();
571     }
572 
573 
574     private int getMinKeyInNode(Node node) {
575         List<KeyAndValue> keyAndValues = node.getKeyAndValue();
576         return keyAndValues.get(0).getKey();
577     }
578 
579     private int getMaxKeyInNode(Node node) {
580         List<KeyAndValue> keyAndValues = node.getKeyAndValue();
581         return keyAndValues.get(keyAndValues.size() - 1).getKey();
582     }
583 
584 
585     private int getLeftBoundOfKey(Node node, int key) {
586         int left = 0;
587         List<KeyAndValue> keyAndValues = node.getKeyAndValue();
588         for (int i = 0; i < keyAndValues.size(); i++) {
589             if (keyAndValues.get(i).getKey() <= key && keyAndValues.get(i + 1).getKey() > key) {
590                 left = keyAndValues.get(i).getKey();
591                 break;
592             }
593         }
594         return left;
595     }
596 
597     private int getRightBoundOfKey(Node node, int key) {
598         int right = 0;
599         List<KeyAndValue> keyAndValues = node.getKeyAndValue();
600         for (int i = 0; i < keyAndValues.size(); i++) {
601             if (keyAndValues.get(i).getKey() <= key && keyAndValues.get(i + 1).getKey() > key) {
602                 right = keyAndValues.get(i + 1).getKey();
603                 break;
604             }
605         }
606         return right;
607     }
608 
609 
610     private void delKeyAndValue(List<KeyAndValue> keyAndValues, int key) {
611         for (KeyAndValue keyAndValue : keyAndValues) {
612             if (keyAndValue.getKey() == key) {
613                 keyAndValues.remove(keyAndValue);
614                 break;
615             }
616         }
617     }
618 
619     //找到node的鍵值對中在min和max中的鍵值對
620     private KeyAndValue getKeyAndValueinMinAndMax(Node node, int min, int max) {
621         if (node == null) {
622             return null;
623         }
624         List<KeyAndValue> keyAndValues = node.getKeyAndValue();
625         KeyAndValue keyAndValue = null;
626         for (KeyAndValue k : keyAndValues) {
627             if (k.getKey() > min && k.getKey() <= max) {
628                 keyAndValue = k;
629                 break;
630             }
631         }
632         return keyAndValue;
633     }
634 
635 //    private KeyAndValue getMaxKeyAndValueInChildNode(Node node) {
636 //        if (node.getNodes() == null || node.getNodes().isEmpty()) {
637 //            return null;
638 //        }
639 //        List<KeyAndValue> sortKeyAndValues = new ArrayList<>();
640 //        List<Node> childNodes = node.getNodes();
641 //        for (Node childNode : childNodes) {
642 //            List<KeyAndValue> keyAndValues = childNode.getKeyAndValue();
643 //            KeyAndValue maxKeyAndValue = keyAndValues.get(keyAndValues.size() - 1);
644 //            sortKeyAndValues.add(maxKeyAndValue);
645 //        }
646 //        Collections.sort(sortKeyAndValues);
647 //        return sortKeyAndValues.get(sortKeyAndValues.size() - 1);
648 //    }
649 
650     private KeyAndValue getMinKeyAndValueInChildNode(Node node) {
651         if (node.getNodes() == null || node.getNodes().isEmpty()) {
652             return null;
653         }
654         List<KeyAndValue> sortKeyAndValues = new ArrayList<>();
655         List<Node> childNodes = node.getNodes();
656         for (Node childNode : childNodes) {
657             List<KeyAndValue> keyAndValues = childNode.getKeyAndValue();
658             KeyAndValue minKeyAndValue = keyAndValues.get(0);
659             sortKeyAndValues.add(minKeyAndValue);
660         }
661         Collections.sort(sortKeyAndValues);
662         return sortKeyAndValues.get(0);
663     }
664 
665     private boolean isNeedMerge(Node node) {
666         if (node == null) {
667             return false;
668         }
669         List<KeyAndValue> keyAndValues = node.getKeyAndValue();
670         return keyAndValues.size() < rank / 2;
671     }
672 
673     //判斷一個節點是否有富余的鍵值對
674     private boolean isMoreElement(Node node) {
675         return node != null && (node.getKeyAndValue().size() > rank / 2);
676     }
677 }

  測試代碼:

  1 public class Main {
  2 
  3     public static void main(String[] args) {
  4         Btree btree = new Btree(4 );
  5         KeyAndValue keyAndValue = new KeyAndValue(1,"123");
  6         KeyAndValue keyAndValue1 = new KeyAndValue(2,"123");
  7         KeyAndValue keyAndValue2 = new KeyAndValue(3,"123");
  8         KeyAndValue keyAndValue3 = new KeyAndValue(4,"123");
  9         KeyAndValue keyAndValue4 = new KeyAndValue(5,"123");
 10         KeyAndValue keyAndValue5 = new KeyAndValue(6,"123");
 11         KeyAndValue keyAndValue6 = new KeyAndValue(7,"12300");
 12         KeyAndValue keyAndValue7 = new KeyAndValue(8,"546");
 13         KeyAndValue keyAndValue8 = new KeyAndValue(9,"123");
 14         KeyAndValue keyAndValue9 = new KeyAndValue(10,"123");
 15         KeyAndValue keyAndValue10 = new KeyAndValue(11,"123");
 16         KeyAndValue keyAndValue11 = new KeyAndValue(12,"123");
 17         KeyAndValue keyAndValue12 = new KeyAndValue(13,"123");
 18         KeyAndValue keyAndValue14 = new KeyAndValue(15,"12345");
 19         KeyAndValue keyAndValue15 = new KeyAndValue(16,"12345");
 20         KeyAndValue keyAndValue16 = new KeyAndValue(17,"12345");
 21         KeyAndValue keyAndValue17 = new KeyAndValue(18,"12345");
 22         KeyAndValue keyAndValue18 = new KeyAndValue(19,"12345");
 23         KeyAndValue keyAndValue19 = new KeyAndValue(20,"12345");
 24         KeyAndValue keyAndValue20 = new KeyAndValue(21,"12345");
 25 
 26         btree.insert(keyAndValue);
 27         btree.insert(keyAndValue5);
 28         btree.insert(keyAndValue9);
 29         btree.insert(keyAndValue1);
 30         btree.insert(keyAndValue7);
 31         btree.insert(keyAndValue10);
 32         btree.insert(keyAndValue17);
 33         btree.insert(keyAndValue2);
 34         btree.insert(keyAndValue14);
 35         btree.insert(keyAndValue16);
 36         btree.insert(keyAndValue11);
 37         btree.insert(keyAndValue12);
 38         btree.insert(keyAndValue3);
 39         btree.insert(keyAndValue8);
 40         btree.insert(keyAndValue18);
 41         btree.insert(keyAndValue15);
 42         btree.insert(keyAndValue4);
 43         btree.insert(keyAndValue19);
 44         btree.insert(keyAndValue6);
 45         btree.insert(keyAndValue20);
 46 
 47 
 48         btree.printBtree(btree.getRoot());
 49 
 50         btree.delete(1);
 51         btree.printBtree(btree.getRoot());
 52 
 53         btree.delete(0);
 54         btree.printBtree(btree.getRoot());
 55 
 56         btree.delete(2);
 57         btree.printBtree(btree.getRoot());
 58 
 59         btree.delete(11);
 60         btree.printBtree(btree.getRoot());
 61 
 62         btree.delete(3);
 63         btree.printBtree(btree.getRoot());
 64 
 65         btree.delete(4);
 66         btree.printBtree(btree.getRoot());
 67 
 68         btree.delete(5);
 69         btree.printBtree(btree.getRoot());
 70 
 71         btree.delete(9);
 72         btree.printBtree(btree.getRoot());
 73 
 74         btree.delete(6);
 75         btree.printBtree(btree.getRoot());
 76 
 77         btree.delete(13);
 78         btree.printBtree(btree.getRoot());
 79 
 80         btree.delete(7);
 81         btree.printBtree(btree.getRoot());
 82 
 83         btree.delete(10);
 84         btree.printBtree(btree.getRoot());
 85 
 86         btree.delete(18);
 87         btree.printBtree(btree.getRoot());
 88 
 89         btree.delete(8);
 90         btree.printBtree(btree.getRoot());
 91 
 92         btree.delete(12);
 93         btree.printBtree(btree.getRoot());
 94 
 95         btree.delete(20);
 96         btree.printBtree(btree.getRoot());
 97 
 98         btree.delete(19);
 99         btree.printBtree(btree.getRoot());
100 
101         btree.delete(15);
102         btree.printBtree(btree.getRoot());
103 
104         btree.delete(17);
105         btree.printBtree(btree.getRoot());
106 
107 
108         
110     }
111 }

  測試結果:

8,12
3,6|10|15,18,20|
1,2|3,4,5|6,7|8,9|10,11|12,13|15,16,17|18,19|20,21|
delete:1

8,12
4,6|10|15,18,20|
2,3|4,5|6,7|8,9|10,11|12,13|15,16,17|18,19|20,21|
delete:0

8,12
4,6|10|15,18,20|
2,3|4,5|6,7|8,9|10,11|12,13|15,16,17|18,19|20,21|
delete:2

12
6,8,10|15,18,20|
3,4,5|6,7|8,9|10,11|12,13|15,16,17|18,19|20,21|
delete:11

12
6,8|15,18,20|
3,4,5|6,7|8,9,10|12,13|15,16,17|18,19|20,21|
delete:3

12
6,8|15,18,20|
4,5|6,7|8,9,10|12,13|15,16,17|18,19|20,21|
delete:4

18
8,15|18,20|
5,6,7|8,9,10|12,13|15,16,17|18,19|20,21|
delete:5

18
8,15|18,20|
6,7|8,9,10|12,13|15,16,17|18,19|20,21|
delete:9

18
8,15|18,20|
6,7|8,10|12,13|15,16,17|18,19|20,21|
delete:6

12,15,18,20
7,8,10|12,13|15,16,17|18,19|20,21|
delete:13

10,15,18,20
7,8|10,12|15,16,17|18,19|20,21|
delete:7

15,18,20
8,10,12|15,16,17|18,19|20,21|
delete:10

15,18,20
8,12|15,16,17|18,19|20,21|
delete:18

15,17,20
8,12|15,16|17,19|20,21|
delete:8

17,20
12,15,16|17,19|20,21|
delete:12

17,20
15,16|17,19|20,21|
delete:20

17
15,16|17,19,21|
delete:19

17
15,16|17,21|
delete:15

16,17,21
delete:17

16,21

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM