, V> { // 是否为叶子节点 protected boolean isLeaf; //是否是根节点 protected boolean isRoot; // 父节点 pr_java b+数据落盘">
当前位置:   article > 正文

【大数据存储】Java实现B+树(增、删、单值查询和范围查询)_java b+数据落盘

java b+数据落盘

BPlusNode.java

  1. package BplusTree;
  2. import java.util.*;
  3. @SuppressWarnings("all")
  4. public class BPlusNode<K extends Comparable<K>, V> {
  5. // 是否为叶子节点
  6. protected boolean isLeaf;
  7. //是否是根节点
  8. protected boolean isRoot;
  9. // 父节点
  10. protected BPlusNode<K, V> parent;
  11. // 叶节点的前驱节点
  12. protected BPlusNode<K, V> previous;
  13. // 叶节点的后继节点
  14. protected BPlusNode<K, V> next;
  15. // 节点的关键字列表
  16. protected List<Map.Entry<K, V>> entries;
  17. // 子节点列表
  18. protected List<BPlusNode<K, V>> children;
  19. //构造方法
  20. public BPlusNode(boolean isLeaf) {
  21. this.isLeaf = isLeaf;
  22. entries = new ArrayList();
  23. //如果不是叶子结点,则有孩子列表
  24. if (!isLeaf) {
  25. children = new ArrayList();
  26. }
  27. }
  28. //构造方法
  29. public BPlusNode(boolean isLeaf, boolean isRoot) {
  30. this(isLeaf);
  31. this.isRoot = isRoot;
  32. }
  33. //单值查找,找到key对应的value值
  34. public V query(K key) {
  35. //如果是叶子节点
  36. if (isLeaf) {
  37. //二分查找
  38. int low = 0, high = entries.size() - 1, mid;
  39. int comp;
  40. while (low <= high) {
  41. mid = (low + high) / 2;
  42. comp = entries.get(mid).getKey().compareTo(key);
  43. //等于key值
  44. if (comp == 0) {
  45. //在entries列表中取value值
  46. return entries.get(mid).getValue();
  47. } else if (comp < 0) {
  48. low = mid + 1;
  49. } else {
  50. high = mid - 1;
  51. }
  52. }
  53. //未找到所要查询的对象
  54. return null;
  55. }
  56. //如果不是叶子节点
  57. //如果key小于节点最左边的key,沿第一个子节点继续递归地搜索
  58. if (key.compareTo(entries.get(0).getKey()) < 0) {
  59. return children.get(0).query(key);
  60. //如果key大于等于节点最右边的key,沿最后一个子节点继续递归地搜索
  61. } else if (key.compareTo(entries.get(entries.size() - 1).getKey()) >= 0) {
  62. return children.get(children.size() - 1).query(key);
  63. //否则沿比key大的前一个子节点继续递归地搜索
  64. } else {
  65. //二分查找
  66. int low = 0, high = entries.size() - 1, mid = 0;
  67. int comp;
  68. while (low <= high) {
  69. mid = (low + high) / 2;
  70. comp = entries.get(mid).getKey().compareTo(key);
  71. if (comp == 0) {
  72. return children.get(mid + 1).query(key);
  73. } else if (comp < 0) {
  74. low = mid + 1;
  75. } else {
  76. high = mid - 1;
  77. }
  78. }
  79. return children.get(low).query(key);
  80. }
  81. }
  82. //范围查找
  83. public List<Map.Entry<K, V>> rangeQuery(K startInclude ,K endExclude){
  84. //如果是叶子结点
  85. if(isLeaf) {
  86. //result存放结果
  87. List<Map.Entry<K, V>> result = new ArrayList<>();
  88. int start =findIndex(startInclude);
  89. int end=findIndex(endExclude);
  90. for(int i=start;i<end;i++) {
  91. result.addAll((Collection<? extends Map.Entry<K, V>>) entries.get(i));
  92. }
  93. BPlusNode<K,V> nextLeaf = this.next;
  94. while(nextLeaf!=null){
  95. for(int i=0;i<nextLeaf.entries.size();++i){
  96. if(nextLeaf.entries.get(i).getKey().compareTo(endExclude)<0){
  97. result.addAll((Collection<? extends Map.Entry<K, V>>) nextLeaf.entries.get(i));
  98. }
  99. else{
  100. return result;
  101. }
  102. }
  103. }
  104. }
  105. //如果不是叶子节点
  106. //如果下界仍小于最左边的key,沿第一个子节点继续递归地搜索
  107. if (startInclude.compareTo(entries.get(0).getKey()) < 0) {
  108. return children.get(0).rangeQuery(startInclude,endExclude);
  109. //如果上界还大于等于节点最右边的key,沿最后一个子节点继续递归地搜索
  110. } else if (endExclude.compareTo(entries.get(entries.size() - 1).getKey()) >= 0) {
  111. return children.get(children.size() - 1).rangeQuery(startInclude,endExclude);
  112. //否则沿比下界大的前一个子节点继续递归地搜索
  113. } else {
  114. //二分查找
  115. int low = 0, high = entries.size() - 1, mid = 0;
  116. int comp;
  117. while (low <= high) {
  118. mid = (low + high) / 2;
  119. comp = entries.get(mid).getKey().compareTo(startInclude);
  120. if (comp == 0) {
  121. return children.get(mid + 1).rangeQuery(startInclude,endExclude);
  122. } else if (comp < 0) {
  123. low = mid + 1;
  124. } else {
  125. high = mid - 1;
  126. }
  127. }
  128. return children.get(low).rangeQuery(startInclude,endExclude);
  129. }
  130. }
  131. //二分查找找到key在entries中的位置
  132. protected int findIndex(K key) {
  133. int l = 0;
  134. int r = entries.size() - 1;
  135. int index = entries.size();
  136. while (l <= r) {
  137. int mid = l + ((r - l) >> 1);
  138. if (entries.get(mid).getKey().compareTo(key) >= 0) {
  139. index = mid;
  140. r = mid - 1;
  141. } else {
  142. l = mid + 1;
  143. }
  144. }
  145. return index;
  146. }
  147. //插入 将key value键值对插入tree
  148. public void insertOrUpdate(K key, V value, BPlusTree<K, V> tree) {
  149. //如果是叶子节点
  150. if (isLeaf) {
  151. //小于树的度,不需要分裂,直接插入或更新
  152. if (contains(key) != -1 || entries.size() < tree.getOrder()) {
  153. insertOrUpdate(key, value);
  154. if (tree.getHeight() == 0) {
  155. tree.setHeight(1);
  156. }
  157. return;
  158. }
  159. //需要分裂
  160. //分裂成左右两个节点
  161. BPlusNode<K, V> left = new BPlusNode<K, V>(true);
  162. BPlusNode<K, V> right = new BPlusNode<K, V>(true);
  163. //设置链接
  164. if (previous != null) {
  165. //前驱结点的next指针指向left
  166. previous.next = left;
  167. left.previous = previous;
  168. }
  169. if (next != null) {
  170. //后继结点的pre指针指向right
  171. next.previous = right;
  172. right.next = next;
  173. }
  174. //没有前驱
  175. if (previous == null) {
  176. tree.setHead(left);
  177. }
  178. //left的后继指针指向right
  179. left.next = right;
  180. //right的前驱指针指向left
  181. right.previous = left;
  182. //pre和next置空
  183. previous = null;
  184. next = null;
  185. //把原节点关键字复制到到分裂出来的两个新节点
  186. copy2Nodes(key, value, left, right, tree);
  187. //如果不是根节点
  188. if (parent != null) {
  189. //调整父子节点关系
  190. //在父节点的children序列中的位置
  191. int index = parent.children.indexOf(this);
  192. //移除当前结点
  193. parent.children.remove(this);
  194. //更新左右新结点的parent
  195. left.parent = parent;
  196. right.parent = parent;
  197. //在父节点的children序列中添加两个新结点
  198. parent.children.add(index, left);
  199. parent.children.add(index + 1, right);
  200. //在父节点的关键字列表的index位置中添加右结点的第一个关键字
  201. parent.entries.add(index, right.entries.get(0));
  202. entries = null; //删除当前节点的关键字信息
  203. children = null; //删除当前节点的孩子节点引用
  204. //父节点插入或更新关键字
  205. parent.updateInsert(tree);
  206. parent = null; //删除当前节点的父节点引用
  207. //如果是根节点
  208. } else {
  209. isRoot = false;
  210. //新建根节点
  211. BPlusNode<K, V> parent = new BPlusNode<K, V>(false, true);
  212. tree.setRoot(parent);
  213. //把相应的指针和序列更新
  214. left.parent = parent;
  215. right.parent = parent;
  216. parent.children.add(left);
  217. parent.children.add(right);
  218. parent.entries.add(right.entries.get(0));
  219. entries = null;
  220. children = null;
  221. }
  222. return;
  223. }
  224. //如果不是叶子节点
  225. //如果key小于等于节点最左边的key,沿第一个子节点继续递归地搜索
  226. if (key.compareTo(entries.get(0).getKey()) < 0) {
  227. children.get(0).insertOrUpdate(key, value, tree);
  228. //如果key大于节点最右边的key,沿最后一个子节点继续递归地搜索
  229. } else if (key.compareTo(entries.get(entries.size() - 1).getKey()) >= 0) {
  230. children.get(children.size() - 1).insertOrUpdate(key, value, tree);
  231. //否则沿比key大的前一个子节点继续递归地搜索
  232. } else {
  233. //二分查找
  234. int low = 0, high = entries.size() - 1, mid = 0;
  235. int comp;
  236. while (low <= high) {
  237. mid = (low + high) / 2;
  238. comp = entries.get(mid).getKey().compareTo(key);
  239. if (comp == 0) {
  240. children.get(mid + 1).insertOrUpdate(key, value, tree);
  241. break;
  242. } else if (comp < 0) {
  243. low = mid + 1;
  244. } else {
  245. high = mid - 1;
  246. }
  247. }
  248. if (low > high) {
  249. children.get(low).insertOrUpdate(key, value, tree);
  250. }
  251. }
  252. }
  253. //把原节点关键字复制到到分裂出来的两个新节点
  254. private void copy2Nodes(K key, V value, BPlusNode<K, V> left,
  255. BPlusNode<K, V> right, BPlusTree<K, V> tree) {
  256. //左右两个节点关键字长度,比方说原结点有5个数,则left分2个,right分3个
  257. int leftSize = (tree.getOrder() + 1) / 2 + (tree.getOrder() + 1) % 2;
  258. boolean b = false;//用于记录新元素是否已经被插入
  259. for (int i = 0; i < entries.size(); i++) {
  260. //左结点
  261. if (leftSize != 0) {
  262. leftSize--;
  263. if (!b && entries.get(i).getKey().compareTo(key) > 0) {
  264. //在左节点的entries序列中新建一个存放新元素
  265. left.entries.add(new AbstractMap.SimpleEntry<K, V>(key, value));
  266. b = true;
  267. i--;
  268. } else {
  269. left.entries.add(entries.get(i));
  270. }
  271. //右结点
  272. } else {
  273. if (!b && entries.get(i).getKey().compareTo(key) > 0) {
  274. //在右节点的entries序列中新建一个存放新元素
  275. right.entries.add(new AbstractMap.SimpleEntry<K, V>(key, value));
  276. b = true;
  277. i--;
  278. } else {
  279. right.entries.add(entries.get(i));
  280. }
  281. }
  282. }
  283. //新元素仍没插入,说明新元素最大,把它放在右节点
  284. if (!b) {
  285. right.entries.add(new AbstractMap.SimpleEntry<K, V>(key, value));
  286. }
  287. }
  288. /**
  289. * 插入节点后中间节点的更新
  290. */
  291. protected void updateInsert(BPlusTree<K, V> tree) {
  292. //如果子节点数超出阶数,则需要分裂该节点
  293. if (children.size() > tree.getOrder()) {
  294. //分裂成左右两个节点
  295. BPlusNode<K, V> left = new BPlusNode<K, V>(false);
  296. BPlusNode<K, V> right = new BPlusNode<K, V>(false);
  297. //左右两个节点子节点的长度
  298. int leftSize = (tree.getOrder() + 1) / 2 + (tree.getOrder() + 1) % 2;
  299. int rightSize = (tree.getOrder() + 1) / 2;
  300. //复制子节点到分裂出来的新节点,并更新关键字
  301. for (int i = 0; i < leftSize; i++) {
  302. left.children.add(children.get(i));
  303. //把每个孩子的parent指针指向left
  304. children.get(i).parent = left;
  305. }
  306. for (int i = 0; i < rightSize; i++) {
  307. right.children.add(children.get(leftSize + i));
  308. //把每个孩子的parent指针指向right
  309. children.get(leftSize + i).parent = right;
  310. }
  311. for (int i = 0; i < leftSize - 1; i++) {
  312. //更新左节点的entries列表
  313. left.entries.add(entries.get(i));
  314. }
  315. for (int i = 0; i < rightSize - 1; i++) {
  316. //更新右节点的entries列表
  317. right.entries.add(entries.get(leftSize + i));
  318. }
  319. //如果不是根节点
  320. if (parent != null) {
  321. //调整父子节点关系
  322. int index = parent.children.indexOf(this);
  323. //在父节点的children列表中移除当前结点
  324. parent.children.remove(this);
  325. //更新指针指向
  326. left.parent = parent;
  327. right.parent = parent;
  328. //更新列表
  329. parent.children.add(index, left);
  330. parent.children.add(index + 1, right);
  331. parent.entries.add(index, entries.get(leftSize - 1));
  332. //原来的置空
  333. entries = null;
  334. children = null;
  335. //递归调用 父节点更新关键字
  336. parent.updateInsert(tree);
  337. parent = null;
  338. //如果是根节点
  339. } else {
  340. isRoot = false;
  341. //新建根节点
  342. BPlusNode<K, V> parent = new BPlusNode<K, V>(false, true);
  343. tree.setRoot(parent);
  344. tree.setHeight(tree.getHeight() + 1);
  345. //更新
  346. left.parent = parent;
  347. right.parent = parent;
  348. parent.children.add(left);
  349. parent.children.add(right);
  350. parent.entries.add(entries.get(leftSize - 1));
  351. //原来的置空
  352. entries = null;
  353. children = null;
  354. }
  355. }
  356. }
  357. /**
  358. * 删除节点后中间节点的更新
  359. */
  360. protected void updateRemove(BPlusTree<K, V> tree) {
  361. // 如果子节点数小于M / 2或者小于2,则需要合并节点
  362. if (children.size() < tree.getOrder() / 2 || children.size() < 2) {
  363. if (isRoot) {
  364. // 如果是根节点并且子节点数大于等于2,无需合并
  365. if (children.size() >= 2) return;
  366. // 否则与子节点合并
  367. //新建根节点
  368. BPlusNode<K, V> root = children.get(0);
  369. tree.setRoot(root);
  370. tree.setHeight(tree.getHeight() - 1);
  371. root.parent = null;
  372. root.isRoot = true;
  373. //原来的置空
  374. entries = null;
  375. children = null;
  376. return;
  377. }
  378. //计算前后节点
  379. //当前结点在父节点的children序列中的位置
  380. int currIdx = parent.children.indexOf(this);
  381. int prevIdx = currIdx - 1;
  382. int nextIdx = currIdx + 1;
  383. //新建前驱和后继
  384. BPlusNode<K, V> previous = null, next = null;
  385. if (prevIdx >= 0) {
  386. previous = parent.children.get(prevIdx);
  387. }
  388. if (nextIdx < parent.children.size()) {
  389. next = parent.children.get(nextIdx);
  390. }
  391. // 如果前驱节点子节点数大于M / 2并且大于2,则从其处借补
  392. if (previous != null
  393. && previous.children.size() > tree.getOrder() / 2
  394. && previous.children.size() > 2) {
  395. //前驱叶子节点末尾节点添加到首位
  396. int idx = previous.children.size() - 1;
  397. //新建借的结点
  398. BPlusNode<K, V> borrow = previous.children.get(idx);
  399. //借走了,从前驱结点的children序列中移除
  400. previous.children.remove(idx);
  401. //借过来了,更新相关
  402. borrow.parent = this;
  403. children.add(0, borrow);
  404. int preIndex = parent.children.indexOf(previous);
  405. entries.add(0, parent.entries.get(preIndex));
  406. parent.entries.set(preIndex, previous.entries.remove(idx - 1));
  407. return;
  408. }
  409. // 同理,如果后继节点子节点数大于M / 2并且大于2,则从其处借补
  410. if (next != null
  411. && next.children.size() > tree.getOrder() / 2
  412. && next.children.size() > 2) {
  413. //后叶子节点首位添加到末尾
  414. BPlusNode<K, V> borrow = next.children.get(0);
  415. next.children.remove(0);
  416. borrow.parent = this;
  417. children.add(borrow);
  418. int preIndex = parent.children.indexOf(this);
  419. entries.add(parent.entries.get(preIndex));
  420. parent.entries.set(preIndex, next.entries.remove(0));
  421. return;
  422. }
  423. // 如果前驱结点不够借,就同前驱节点合并
  424. if (previous != null
  425. && (previous.children.size() <= tree.getOrder() / 2
  426. || previous.children.size() <= 2)) {
  427. for (int i = 0; i < children.size(); i++) {
  428. previous.children.add(children.get(i));
  429. }
  430. for (int i = 0; i < previous.children.size(); i++) {
  431. previous.children.get(i).parent = this;
  432. }
  433. int indexPre = parent.children.indexOf(previous);
  434. previous.entries.add(parent.entries.get(indexPre));
  435. for (int i = 0; i < entries.size(); i++) {
  436. previous.entries.add(entries.get(i));
  437. }
  438. children = previous.children;
  439. entries = previous.entries;
  440. //更新父节点的关键字列表
  441. parent.children.remove(previous);
  442. previous.parent = null;
  443. previous.children = null;
  444. previous.entries = null;
  445. //合并了,父节点的孩子就少一个
  446. parent.entries.remove(parent.children.indexOf(this));
  447. if ((!parent.isRoot
  448. && (parent.children.size() >= tree.getOrder() / 2
  449. && parent.children.size() >= 2))
  450. || parent.isRoot && parent.children.size() >= 2) {
  451. return;
  452. }
  453. //递归调用
  454. parent.updateRemove(tree);
  455. return;
  456. }
  457. // 同理,后继结点不够借,就同后面节点合并
  458. if (next != null
  459. && (next.children.size() <= tree.getOrder() / 2
  460. || next.children.size() <= 2)) {
  461. for (int i = 0; i < next.children.size(); i++) {
  462. BPlusNode<K, V> child = next.children.get(i);
  463. children.add(child);
  464. child.parent = this;
  465. }
  466. int index = parent.children.indexOf(this);
  467. entries.add(parent.entries.get(index));
  468. for (int i = 0; i < next.entries.size(); i++) {
  469. entries.add(next.entries.get(i));
  470. }
  471. parent.children.remove(next);
  472. next.parent = null;
  473. next.children = null;
  474. next.entries = null;
  475. parent.entries.remove(parent.children.indexOf(this));
  476. if ((!parent.isRoot && (parent.children.size() >= tree.getOrder() / 2
  477. && parent.children.size() >= 2))
  478. || parent.isRoot && parent.children.size() >= 2) {
  479. return;
  480. }
  481. parent.updateRemove(tree);
  482. return;
  483. }
  484. }
  485. }
  486. //在叶子中删除key
  487. public V remove(K key, BPlusTree<K, V> tree) {
  488. //如果是叶子节点
  489. if (isLeaf) {
  490. //如果不包含该关键字,则直接返回
  491. if (contains(key) == -1) {
  492. return null;
  493. }
  494. //如果既是叶子节点又是根节点,直接删除
  495. if (isRoot) {
  496. if (entries.size() == 1) {
  497. tree.setHeight(0);
  498. }
  499. return remove(key);
  500. }
  501. //如果关键字数大于M / 2,直接删除
  502. if (entries.size() > tree.getOrder() / 2 && entries.size() > 2) {
  503. return remove(key);
  504. }
  505. //如果自身关键字数小于M / 2,并且前驱节点关键字数大于M / 2,则从其处借补
  506. if (previous != null &&
  507. previous.parent == parent
  508. && previous.entries.size() > tree.getOrder() / 2
  509. && previous.entries.size() > 2) {
  510. //添加到首位
  511. int size = previous.entries.size();
  512. entries.add(0, previous.entries.remove(size - 1));
  513. int index = parent.children.indexOf(previous);
  514. parent.entries.set(index, entries.get(0));
  515. return remove(key);
  516. }
  517. //如果自身关键字数小于M / 2,并且后节点关键字数大于M / 2,则从其处借补
  518. if (next != null
  519. && next.parent == parent
  520. && next.entries.size() > tree.getOrder() / 2
  521. && next.entries.size() > 2) {
  522. entries.add(next.entries.remove(0));
  523. int index = parent.children.indexOf(this);
  524. parent.entries.set(index, next.entries.get(0));
  525. return remove(key);
  526. }
  527. //前驱不够借,就同前面节点合并
  528. if (previous != null
  529. && previous.parent == parent
  530. && (previous.entries.size() <= tree.getOrder() / 2
  531. || previous.entries.size() <= 2)) {
  532. V returnValue = remove(key);
  533. for (int i = 0; i < entries.size(); i++) {
  534. //将当前节点的关键字添加到前节点的末尾
  535. previous.entries.add(entries.get(i));
  536. }
  537. entries = previous.entries;
  538. parent.children.remove(previous);
  539. previous.parent = null;
  540. previous.entries = null;
  541. //更新链表
  542. if (previous.previous != null) {
  543. BPlusNode<K, V> temp = previous;
  544. temp.previous.next = this;
  545. previous = temp.previous;
  546. temp.previous = null;
  547. temp.next = null;
  548. } else {
  549. tree.setHead(this);
  550. previous.next = null;
  551. previous = null;
  552. }
  553. parent.entries.remove(parent.children.indexOf(this));
  554. if ((!parent.isRoot && (parent.children.size() >= tree.getOrder() / 2
  555. && parent.children.size() >= 2))
  556. || parent.isRoot && parent.children.size() >= 2) {
  557. return returnValue;
  558. }
  559. //父节点要调整
  560. parent.updateRemove(tree);
  561. return returnValue;
  562. }
  563. //后继结点不够借,就同后面节点合并
  564. if (next != null
  565. && next.parent == parent
  566. && (next.entries.size() <= tree.getOrder() / 2
  567. || next.entries.size() <= 2)) {
  568. V returnValue = remove(key);
  569. for (int i = 0; i < next.entries.size(); i++) {
  570. //从首位开始添加到末尾
  571. entries.add(next.entries.get(i));
  572. }
  573. next.parent = null;
  574. next.entries = null;
  575. parent.children.remove(next);
  576. //更新链表
  577. if (next.next != null) {
  578. BPlusNode<K, V> temp = next;
  579. temp.next.previous = this;
  580. next = temp.next;
  581. temp.previous = null;
  582. temp.next = null;
  583. } else {
  584. next.previous = null;
  585. next = null;
  586. }
  587. //更新父节点的关键字列表
  588. parent.entries.remove(parent.children.indexOf(this));
  589. if ((!parent.isRoot && (parent.children.size() >= tree.getOrder() / 2
  590. && parent.children.size() >= 2))
  591. || parent.isRoot && parent.children.size() >= 2) {
  592. return returnValue;
  593. }
  594. parent.updateRemove(tree);
  595. return returnValue;
  596. }
  597. }
  598. /*如果不是叶子节点*/
  599. //如果key小于等于节点最左边的key,沿第一个子节点继续搜索
  600. if (key.compareTo(entries.get(0).getKey()) < 0) {
  601. return children.get(0).remove(key, tree);
  602. //如果key大于节点最右边的key,沿最后一个子节点继续搜索
  603. } else if (key.compareTo(entries.get(entries.size() - 1).getKey()) >= 0) {
  604. return children.get(children.size() - 1).remove(key, tree);
  605. //否则沿比key大的前一个子节点继续搜索
  606. } else {
  607. //二分查找
  608. int low = 0, high = entries.size() - 1, mid = 0;
  609. int comp;
  610. while (low <= high) {
  611. mid = (low + high) / 2;
  612. comp = entries.get(mid).getKey().compareTo(key);
  613. if (comp == 0) {
  614. return children.get(mid + 1).remove(key, tree);
  615. } else if (comp < 0) {
  616. low = mid + 1;
  617. } else {
  618. high = mid - 1;
  619. }
  620. }
  621. return children.get(low).remove(key, tree);
  622. }
  623. }
  624. // 判断当前节点是否包含该关键字
  625. protected int contains(K key) {
  626. int low = 0, high = entries.size() - 1, mid;
  627. int comp;
  628. while (low <= high) {
  629. mid = (low + high) / 2;
  630. comp = entries.get(mid).getKey().compareTo(key);
  631. if (comp == 0) {
  632. return mid;
  633. } else if (comp < 0) {
  634. low = mid + 1;
  635. } else {
  636. high = mid - 1;
  637. }
  638. }
  639. return -1;
  640. }
  641. // 插入到当前节点的关键字中
  642. protected void insertOrUpdate(K key, V value) {
  643. //二叉查找,插入
  644. int low = 0, high = entries.size() - 1, mid;
  645. int comp;
  646. while (low <= high) {
  647. mid = (low + high) / 2;
  648. comp = entries.get(mid).getKey().compareTo(key);
  649. if (comp == 0) {
  650. entries.get(mid).setValue(value);
  651. break;
  652. } else if (comp < 0) {
  653. low = mid + 1;
  654. } else {
  655. high = mid - 1;
  656. }
  657. }
  658. if (low > high) {
  659. entries.add(low, new AbstractMap.SimpleEntry<K, V>(key, value));
  660. }
  661. }
  662. // 返回待删除节点的value值
  663. protected V remove(K key) {
  664. int low = 0, high = entries.size() - 1, mid;
  665. int comp;
  666. while (low <= high) {
  667. mid = (low + high) / 2;
  668. comp = entries.get(mid).getKey().compareTo(key);
  669. if (comp == 0) {
  670. return entries.remove(mid).getValue();
  671. } else if (comp < 0) {
  672. low = mid + 1;
  673. } else {
  674. high = mid - 1;
  675. }
  676. }
  677. return null;
  678. }
  679. public String toString() {
  680. StringBuilder sb = new StringBuilder();
  681. sb.append("isRoot: ");
  682. sb.append(isRoot);
  683. sb.append(", ");
  684. sb.append("isLeaf: ");
  685. sb.append(isLeaf);
  686. sb.append(", ");
  687. sb.append("keys: ");
  688. for (Map.Entry<K, V> entry : entries) {
  689. sb.append(entry.getKey());
  690. sb.append(", ");
  691. }
  692. sb.append(", ");
  693. return sb.toString();
  694. }
  695. //打印信息
  696. public void printBPlusTree(int index) {
  697. if (this.isLeaf) {
  698. System.out.print("层级:" + index + ",叶子节点,keys为: ");
  699. for (int i = 0; i < entries.size(); ++i)
  700. System.out.print(entries.get(i) + " ");
  701. System.out.println();
  702. } else {
  703. System.out.print("层级:" + index + ",非叶子节点,keys为: ");
  704. for (int i = 0; i < entries.size(); ++i)
  705. System.out.print(entries.get(i) + " ");
  706. System.out.println();
  707. for (int i = 0; i < children.size(); ++i)
  708. children.get(i).printBPlusTree(index + 1);
  709. }
  710. }
  711. }

BPlusTree.java

  1. package BplusTree;
  2. /**
  3. * B+树的定义:
  4. * 1.任意非叶子结点最多有M个子节点;且M>2;M为B+树的阶数
  5. * 2.除根结点以外的非叶子结点至少有 (M+1)/2个子节点;
  6. * 3.根结点至少有2个子节点;
  7. * 4.除根节点外每个结点存放至少(M-1)/2和至多M-1个关键字;(至少1个关键字)
  8. * 5.非叶子结点的子树指针比关键字多1个;
  9. * 6.非叶子节点的所有key按升序存放,假设节点的关键字分别为K[0], K[1] … K[M-2],指向子女的指针分别为P[0], P[1]…P[M-1]。则有:
  10. *    P[0] < K[0] <= P[1] < K[1] …..< K[M-2] <= P[M-1]
  11. * 7.所有叶子结点位于同一层;
  12. * 8.为所有叶子结点增加一个链指针;
  13. * 9.所有关键字都在叶子结点出现
  14. */
  15. @SuppressWarnings("all")
  16. public class BPlusTree<K extends Comparable<K>, V> {
  17. // 根节点
  18. protected BPlusNode<K, V> root;
  19. // 每个空间最多可以存多少数据
  20. protected int order;
  21. // 叶子节点的链表头
  22. protected BPlusNode<K, V> head;
  23. // 树高
  24. protected int height = 0;
  25. public BPlusNode<K, V> getHead() {
  26. return head;
  27. }
  28. public void setHead(BPlusNode<K, V> head) {
  29. this.head = head;
  30. }
  31. public BPlusNode<K, V> getRoot() {
  32. return root;
  33. }
  34. public void setRoot(BPlusNode<K, V> root) {
  35. this.root = root;
  36. }
  37. public int getOrder() {
  38. return order;
  39. }
  40. public void setOrder(int order) {
  41. this.order = order;
  42. }
  43. public void setHeight(int height) {
  44. this.height = height;
  45. }
  46. public int getHeight() {
  47. return height;
  48. }
  49. public V query(K key) {return root.query(key);}
  50. public V remove(K key) {
  51. return root.remove(key, this);
  52. }
  53. public void insertOrUpdate(K key, V value) {
  54. root.insertOrUpdate(key, value, this);
  55. }
  56. public BPlusTree(int order) {
  57. if (order < 3) {
  58. System.out.print("度数要大于2!");
  59. System.exit(0);
  60. }
  61. this.order = order;
  62. root = new BPlusNode<K, V>(true, true);
  63. head = root;
  64. }
  65. public void printBPlusTree() {
  66. this.root.printBPlusTree(0);
  67. }
  68. }

BPlusTreeTest.java

  1. package BplusTree;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import java.util.Random;
  5. public class BPlusTreeTest {
  6. // 测试
  7. public static void main(String[] args) {
  8. int size = 12;
  9. int order = 4;
  10. testRandomInsert(size, order);
  11. //testRandomSearch(size, order);
  12. //testRandomRemove(size, order);
  13. }
  14. private static void testRandomRemove(int size, int order) {
  15. BPlusTree<Integer, Integer> tree = new BPlusTree<Integer, Integer>(order);
  16. System.out.println("\nTest random remove " + size + " datas, of order:"
  17. + order);
  18. Random random = new Random();
  19. boolean[] a = new boolean[size + 10];
  20. List<Integer> list = new ArrayList<Integer>();
  21. int randomNumber = 0;
  22. System.out.println("Begin random insert...");
  23. for (int i = 0; i < size; i++) {
  24. randomNumber = random.nextInt(size);
  25. a[randomNumber] = true;
  26. list.add(randomNumber);
  27. tree.insertOrUpdate(randomNumber, randomNumber);
  28. }
  29. tree.printBPlusTree();
  30. System.out.println("Begin random remove...");
  31. long current = System.currentTimeMillis();
  32. for (int j = 0; j < size; j++) {
  33. randomNumber = list.get(j);
  34. if (a[randomNumber]) {
  35. if (tree.remove(randomNumber) == null) {
  36. System.err.println("得不到数据:" + randomNumber);
  37. break;
  38. } else {
  39. a[randomNumber] = false;
  40. }
  41. }
  42. }
  43. long duration = System.currentTimeMillis() - current;
  44. System.out.println("time elpsed for duration: " + duration);
  45. tree.printBPlusTree();
  46. System.out.println("树高:"+tree.getHeight());
  47. }
  48. private static void testRandomSearch(int size, int order) {
  49. BPlusTree<Integer, Integer> tree = new BPlusTree<Integer, Integer>(order);
  50. System.out.println("\nTest random search " + size + " datas, of order:"
  51. + order);
  52. Random random = new Random();
  53. boolean[] a = new boolean[size + 10];
  54. int randomNumber = 0;
  55. System.out.println("Begin random insert...");
  56. for (int i = 0; i < size; i++) {
  57. randomNumber = random.nextInt(size);
  58. a[randomNumber] = true;
  59. tree.insertOrUpdate(randomNumber, randomNumber);
  60. }
  61. tree.printBPlusTree();
  62. System.out.println("Begin random search...");
  63. long current = System.currentTimeMillis();
  64. for (int j = 0; j < size; j++) {
  65. randomNumber = random.nextInt(size);
  66. if (a[randomNumber]) {
  67. if (tree.query(randomNumber) == null) {
  68. System.err.println("得不到数据:" + randomNumber);
  69. break;
  70. }
  71. }
  72. }
  73. long duration = System.currentTimeMillis() - current;
  74. System.out.println("time elpsed for duration: " + duration);
  75. }
  76. private static void testRandomInsert(int size, int order) {
  77. BPlusTree<Integer, Integer> tree = new BPlusTree<Integer, Integer>(order);
  78. System.out.println("\nTest random insert " + size + " datas, of order:"
  79. + order);
  80. Random random = new Random();
  81. int randomNumber = 0;
  82. for (int i = 0; i < size; i++) {
  83. randomNumber = random.nextInt(size * 10);
  84. System.out.print(randomNumber + " ");
  85. tree.insertOrUpdate(randomNumber, randomNumber);
  86. }
  87. tree.printBPlusTree();
  88. System.out.println("树高:"+tree.getHeight());
  89. }
  90. }

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/1007022
推荐阅读
相关标签
  

闽ICP备14008679号