B+树的算法(java实现)

Posted ll9507

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

 

以上是关于B+树的算法(java实现)的主要内容,如果未能解决你的问题,请参考以下文章

用java实现二叉树的遍历算法

树的存储结构的设计及递归遍历(前序,后序,层序)算法实现——Java数据结构与算法笔记

树的存储结构的设计及递归遍历(前序,后序,层序)算法实现——Java数据结构与算法笔记

树的存储结构的设计及递归遍历(前序,后序,层序)算法实现——Java数据结构与算法笔记

树的存储结构的设计及递归遍历(前序,后序,层序)算法实现——Java数据结构与算法笔记

最小生成树的 Krusal 算法和 Prim 算法 Java 实现