1 package edu.algorithms.btree;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 /**
7 * BTree类
8 *
9 * @author lingfeng
10 *
11 */
12 public class BTree {
13
14 /**BTree 基础参数信息配置
15 最小度数 t=2时,称作2-3-4数,表示只能存在2、3、4子女数**/
16 private int t = 2;
17
18 /**非根节点最小关键字数**/
19 private int minKeys = t-1;
20
21 /**内节点最大关键字数**/
22 private int maxKeys = 2*t - 1;
23
24 /**树根节点**/
25 private BTreeNode root;
26
27 /**构造函数**/
28 public BTree(){
29 //初始化
30 root = new BTreeNode();
31 root.setLeaf(true);
32 }
33 /**构造函数 t 最小度数**/
34 public BTree(int t){
35 this();
36 this.t = t;
37 minKeys = t - 1;
38 maxKeys = 2*t - 1;
39 }
40
41 /**插入元素
42 *
43 * 1.元素存在,插入元素
44 * 2.元素不存在,插入元素
45 *
46 * **/
47 public void insertNode(Integer key){
48 if(root.size() == maxKeys){ //根节点已满
49 //进行根节点分割
50 BTreeNode tmpNode = new BTreeNode();
51 tmpNode.setLeaf(false);
52 tmpNode.getChildrens().add(root);
53 btreeSplitChild(tmpNode, 0, root);
54 root = tmpNode;
55 }
56 insertRootNotFull(root, key);
57 }
58
59 public void insertRootNotFull(BTreeNode node, int key){
60
61 //如果该节点为叶子节点
62 if(node.isLeaf()){
63 //寻找当前节点所有关键字
64 ResultSearch result = divideSearch(node.getKeys(), key);
65 //查询结果:成功 返回已经存在关键字位置
66 if(result.result == true){
67
68 }else{ //查询结果:失败 返回插入位置
69 node.insertKey(key, result.index);
70 }
71
72 }else{
73 //寻找当前节点所有关键字
74 ResultSearch result = divideSearch(node.getKeys(), key);
75 //查询结果:成功 返回已经存在关键字位置
76 if(result.result == true){
77
78 }else{ //查询结果:失败 返回插入子女节点的位置
79 //判断子女状态
80 BTreeNode childNode = node.childAt(result.index);
81 if(node.childAt(result.index).size() == (2*t - 1)){
82 btreeSplitChild(node, result.index, childNode);
83 if(key > node.keyAt(result.index)){ //判断key落在 前半部分 或 后半部分
84 childNode = node.childAt(result.index + 1);
85 }
86 }
87 insertRootNotFull(childNode, key);
88 }
89 }
90 }
91 /**查询元素 (BTree查询)
92 *
93 * 1.先查询节点的关键字列表
94 * 2.失败则,查询子女节点;成功则,返回值
95 * 3.递归搜索
96 *
97 * **/
98 public Integer search(BTreeNode node,Integer key){
99 List<Integer> keys_tmp = node.getKeys();
100 ResultSearch result = divideSearch(keys_tmp, key);
101 if(result.result){
102 return result.index;
103 }else{
104 return search(node.childAt(result.index), key);
105 }
106 }
107 /**二分查询
108 * 参数 元素列表、所需要查询元素的值
109 *
110 * **/
111 public ResultSearch divideSearch(List<Integer> elements, int key){
112
113 int start = 0; //扫描起始位置
114 int end = 0; //扫描结束位置
115
116 end = elements.size() - 1;
117
118 int mid = 0;
119 while(start<=end){
120 mid = (start + end)/2;
121 if(elements.get(mid) == key){ //满足等值条件
122 break;
123 }else if(elements.get(mid) > key){ //在列表前半部分
124 //改变扫描结束位置
125 end = mid - 1;
126 }else if(elements.get(mid) <= key){
127 //改变扫描开始位置
128 start = mid + 1;
129 }
130 }
131
132 boolean result = false;
133 Integer index = 0;
134
135 if(start<=end){ //二分查找成功
136 result = true;
137 index = mid;
138 }else{ //查找失败,不存在元素
139 result = false;
140 index = start;
141 }
142
143 return new ResultSearch(result,index);
144 }
145
146 /**
147 * 节点分割函数
148 * @param parentNode 被分割节点的父节点
149 * @param index 被分割节点在父节点的第index个子女索引位置
150 * @param Node 被分割节点
151 */
152 public void btreeSplitChild(BTreeNode parentNode, int index, BTreeNode node){
153
154 //新建一个节点,保存分割后[t+1 2t-1]数据
155 BTreeNode subNode = new BTreeNode();
156 //必须加上
157 subNode.setLeaf(node.isLeaf());
158
159 for(int i=1; i<=minKeys ; i++){
160 subNode.getKeys().add(node.keyAt(t + i -1));
161 }
162 //保存分割点值[t]
163 Integer key = node.keyAt(t - 1);
164 //删除被分割节点的[t 2t-1]数据
165 for(int i= maxKeys - 1; i>=minKeys; --i){
166 node.getKeys().remove(i);
167 }
168 if(!node.isLeaf()){ //如果满节点不是叶节点,关键字分割后,需要将其子女进行操作
169
170 //subNode应该拥有后半部分的子女
171 for(int i=0 ; i<minKeys+1 ; ++i){
172 subNode.getChildrens().add(node.childAt(i+t));
173 }
174 //并删除node后半部分的子女
175 for(int i=maxKeys ; i>=minKeys+1; --i){
176 node.getChildrens().remove(i);
177 }
178 }else{
179
180 }
181 //将[t]数据加入父节点中去
182 parentNode.insertKey(key, index);
183 //将新节点关联到父节点index+1子女中
184 parentNode.insertChild(subNode, index+1);
185 }
186 public void delete(Integer key){
187 delete(root, key);
188 }
189
190 public void delete(BTreeNode node, Integer key){
191 //删除关键字时,必须保证关键字大于等于t
192 assert node.size() >=t || node == root;
193
194 //对当前节点进行二分查找
195 ResultSearch resultSearch = divideSearch(node.getKeys(), key);
196
197 //成功
198 if(resultSearch.result){
199
200 //如果当前节点属于叶子节点,可以直接进行删除
201 if(node.isLeaf()){
202 node.getKeys().remove(resultSearch.index.intValue());
203 }else{
204 //如果不是叶子节点 ,判断前于key子节点状态
205 BTreeNode leftChildNode = node.childAt(resultSearch.index);
206 if(leftChildNode.size() >= t){
207
208 //从leftChildNode进行借值 代替当前需要删除的关键字
209 //删除当前节点关键字
210 node.getKeys().remove(resultSearch.index.intValue());
211 node.insertKey(leftChildNode.keyAt(leftChildNode.size()-1), resultSearch.index);
212 delete(leftChildNode, leftChildNode.keyAt(leftChildNode.size()-1));
213 }else{
214
215 BTreeNode rightChildNode = node.childAt(resultSearch.index + 1);
216 if(rightChildNode.size() >= t){
217
218 //从rightChildNode进行借值 代替当前需要删除的关键字
219 node.getKeys().remove(resultSearch.index.intValue());
220 node.insertKey(rightChildNode.keyAt(0), resultSearch.index);
221 delete(rightChildNode, rightChildNode.keyAt(0));
222 }else{
223
224 //对于索引的左右子节点的数量都等于t-1
225 //合适进行合并
226 //1.将父节点删除 将节点右子节点删除
227 node.getKeys().remove(resultSearch.index.intValue());
228 node.getChildrens().remove(resultSearch.index.intValue() + 1);
229 //2.将父节点添加到左子节点上
230 leftChildNode.getKeys().add(key);
231 //3.将删除的右子节点添加到左子节点上
232 for(int i=0 ; i<rightChildNode.size() ; i++){
233 leftChildNode.getKeys().add(rightChildNode.getKeys().get(i));
234 }
235 //如果右子节点非叶子节点,需要将其子女继承到左节点之下
236 if(!rightChildNode.isLeaf()){
237 for(int k=0 ; k<=rightChildNode.size() ; k++){
238 leftChildNode.getChildrens().add(rightChildNode.childAt(k));
239 }
240 }
241 //递归删除
242 delete(leftChildNode, key);
243
244 }
245 }
246
247 }
248
249 }else{ //失败
250 if(node.isLeaf()){
251 //不存在删除的对象
252 System.out.println("不存在删除的对象");
253 return ;
254 }
255
256 //获取子节点
257 BTreeNode childNode = node.childAt(resultSearch.index);
258
259 if(root == node && node.size()==0){
260 root = childNode;
261 }
262
263 if(childNode.size() >= t){ //如果满足递归条件
264 delete(childNode, key);
265 }else{
266 //不满足size == t
267 //采取借关键字手段
268
269 BTreeNode subNode = null;
270 int subIndex = 0;
271 //先检测右兄弟节点
272 if(resultSearch.index < node.size()){
273 if(node.childAt(resultSearch.index+1).size() >=t){
274 subNode = node.childAt(resultSearch.index+1);
275 subIndex = resultSearch.index + 1;
276 }
277 }
278 //测试左兄弟节点
279 if(subNode == null){
280 if(resultSearch.index > 0){
281 if(node.childAt(resultSearch.index-1).size() >= t){
282 subNode = node.childAt(resultSearch.index-1);
283 subIndex = resultSearch.index - 1;
284 }
285 }
286 }
287 //测试完成后
288 if(subNode != null){ //存在兄弟节点大于等于t情况
289 //判断节点
290 if(subIndex > resultSearch.index){ //右兄弟
291
292 //将右关键字插入自身
293 childNode.insertKey(node.keyAt(subIndex - 1), childNode.size());
294 node.getKeys().remove(subIndex - 1);
295 node.insertKey(subNode.keyAt(0), subIndex - 1);
296 subNode.getKeys().remove(0);
297
298 //右兄弟非子叶节点,则带有孩子节点
299 if(!subNode.isLeaf()){
300 childNode.getChildrens().add(subNode.getChildrens().get(0));
301 subNode.getChildrens().remove(0);
302 }
303
304 }else{ //左兄弟
305
306 //将左关键字插入自身最前位置
307 childNode.insertKey(node.keyAt(subIndex), 0);
308 node.getKeys().remove(subIndex);
309 node.insertKey(subNode.keyAt(subNode.size()-1), subIndex);
310 subNode.getKeys().remove(subNode.size()-1);
311
312 //如果左兄弟非子叶节点
313 if(!subNode.isLeaf()){
314 childNode.insertChild(subNode.childAt(subNode.size()), 0);
315 subNode.getChildrens().remove(subNode.size()-1);
316 }
317 }
318 delete(childNode, key);
319
320 }else{
321
322 //该节点的左右兄弟节点关键字都为t-1
323 //选择合并方案
324 if(resultSearch.index < node.size()){ //右兄弟存在
325
326 subNode = node.childAt(resultSearch.index + 1);
327
328 //childNode.getKeys().add(node.keyAt(resultSearch.index + 1));
329 childNode.getKeys().add(node.keyAt(resultSearch.index));
330
331 node.getKeys().remove(resultSearch.index.intValue());
332 node.getChildrens().remove(resultSearch.index.intValue());
333
334 for(int i=0 ; i<subNode.size() ; i++){
335 childNode.getKeys().add(subNode.keyAt(i));
336 }
337
338 if(!subNode.isLeaf()){
339 for(int k=0 ; k<=subNode.size(); k++){
340 childNode.getChildrens().add(subNode.childAt(k));
341 }
342 }
343
344 }else{ //左兄弟存在
345
346 subNode = node.childAt(resultSearch.index - 1);
347 childNode.insertKey(node.keyAt(resultSearch.index-1), 0);
348 node.getKeys().remove(resultSearch.index - 1);
349 node.getChildrens().remove(resultSearch.index-1);
350
351 for(int i=subNode.size()-1 ; i>=0 ; --i){
352 childNode.insertKey(subNode.keyAt(i), 0);
353 }
354
355 if(!subNode.isLeaf()){
356 for(int k=subNode.size() ; k>=0 ; --k){
357 childNode.insertChild(subNode.childAt(k),0);
358 }
359 }
360
361 }
362 if(root == node && node.size() == 0){
363 root = childNode;
364 }
365 delete(childNode, key);
366 }
367 }
368
369 }
370 }
371
372 }
373 class BTreeNode{
374
375 /**当前节点keys列表**/
376 private List<Integer> keys;
377
378 /**当前节点的child列表**/
379 private List<BTreeNode> childrens;
380
381 /**是否是叶子节点**/
382 private boolean leaf;
383
384 public BTreeNode(){
385 keys = new ArrayList<Integer>();
386 childrens = new ArrayList<BTreeNode>();
387 leaf = true;
388 }
389 /**
390 * set and get methods
391 *
392 * **/
393 public List<Integer> getKeys() {
394 return keys;
395 }
396 public void setKeys(List<Integer> keys) {
397 this.keys = keys;
398 }
399 public List<BTreeNode> getChildrens() {
400 return childrens;
401 }
402 public void setChildrens(List<BTreeNode> childrens) {
403 this.childrens = childrens;
404 }
405 public boolean isLeaf() {
406 return leaf;
407 }
408 public void setLeaf(boolean leaf) {
409 this.leaf = leaf;
410 }
411
412 /**
413 * 获取子女节点
414 * @param index
415 * @return
416 */
417 public BTreeNode childAt(int index){
418 return childrens.get(index);
419 }
420 /**
421 * 获取关键字
422 * @param index
423 * @return
424 */
425 public Integer keyAt(int index){
426 return keys.get(index);
427 }
428
429 /**
430 * 获取节点关键字数量
431 * @return
432 */
433 public int size(){
434 return keys.size();
435 }
436
437 /**
438 * 插入key到指定的index中去
439 * @param key
440 * @param index
441 */
442 public void insertKey(Integer key, int index){
443 //插入key到指定的索引位置
444 //保存索引前的所有关键字
445 List<Integer> newlist = new ArrayList<Integer>();
446
447 for(int i=0; i<index ; i++){
448 newlist.add(keys.get(i));
449 }
450 //插入关键字
451 newlist.add(key);
452 //保存索引后多关键字
453 for(int i=index ; i<keys.size() ; i++){
454 newlist.add(keys.get(i));
455 }
456 //将新的关键字集合设置为节点关键字集合对象
457 keys = newlist;
458 }
459
460 /**
461 * 插入node子女到指定的index位置
462 * @param node
463 * @param index
464 */
465 public void insertChild(BTreeNode node, int index){
466 //插入child
467 List<BTreeNode> newlist = new ArrayList<BTreeNode>();
468 for(int i=0 ; i< index ; i++){
469 newlist.add(childrens.get(i));
470 }
471 newlist.add(node);
472 for(int i=index ; i<childrens.size() ; i++){
473 newlist.add(childrens.get(i));
474 }
475 childrens = newlist;
476 }
477 }
478 /**
479 * 查询结果类
480 * result 标识成功的状态 true or false
481 * index 成功后返回元素的索引
482 * 失败后返回元素的插入位置
483 * @author lingfeng
484 */
485 class ResultSearch{
486
487 public Integer index;
488 public boolean result;
489
490 public ResultSearch(boolean rs, Integer i){
491 index = i;
492 result = rs;
493 }
494 }