1. 程式人生 > >java b+樹的實現

java b+樹的實現

B+樹的定義:

1.任意非葉子結點最多有M個子節點;且M>2;

2.除根結點以外的非葉子結點至少有 M/2個子節點;

3.根結點至少有2個子節點;

4.除根節點外每個結點存放至少M/2和至多M個關鍵字;(至少2個關鍵字)

5.非葉子結點的子樹指標與關鍵字個數相同;

6.所有結點的關鍵字:K[1], K[2], …, K[M];且K[i] < K[i+1];

7.非葉子結點的子樹指標P[i],指向關鍵字值屬於[K[i], K[i+1])的子樹;

8.所有葉子結點位於同一層;

5.為所有葉子結點增加一個鏈指標;

6.所有關鍵字都在葉子結點出現;

Java實現: 介面: Java程式碼
複製程式碼
收藏程式碼
  1. package com.meidusa.test; 
  2. publicinterface B { 
  3.        public Object get(Comparable key);   //查詢
  4.        publicvoid remove(Comparable key);    //移除
  5.        publicvoid insertOrUpdate(Comparable key, Object obj); //插入或者更新,如果已經存在,就更新,否則插入
package com.meidusa.test;

public interface B {
	   public Object get(Comparable key);   //查詢
	   public void remove(Comparable key);    //移除
	   public void insertOrUpdate(Comparable key, Object obj); //插入或者更新,如果已經存在,就更新,否則插入
}
B+樹: Java程式碼 複製程式碼 收藏程式碼
  1. package com.meidusa.test; 
  2. import java.util.Random; 
  3. publicclass BplusTree implements B { 
  4.     /** 根節點 */
  5.     protected Node root; 
  6.     /** 階數,M值 */
  7.     protectedint order; 
  8.     /** 葉子節點的連結串列頭*/
  9.     protected Node head; 
  10.     public Node getHead() { 
  11.         return head; 
  12.     } 
  13.     public
    void setHead(Node head) { 
  14.         this.head = head; 
  15.     } 
  16.     public Node getRoot() { 
  17.         return root; 
  18.     } 
  19.     publicvoid setRoot(Node root) { 
  20.         this.root = root; 
  21.     } 
  22.     publicint getOrder() { 
  23.         return order; 
  24.     } 
  25.     publicvoid setOrder(int order) { 
  26.         this.order = order; 
  27.     } 
  28.     @Override
  29.     public Object get(Comparable key) { 
  30.         return root.get(key); 
  31.     } 
  32.     @Override
  33.     publicvoid remove(Comparable key) { 
  34.         root.remove(key, this); 
  35.     } 
  36.     @Override
  37.     publicvoid insertOrUpdate(Comparable key, Object obj) { 
  38.         root.insertOrUpdate(key, obj, this); 
  39.     } 
  40.     public BplusTree(int order){ 
  41.         if (order < 3) { 
  42.             System.out.print("order must be greater than 2"); 
  43.             System.exit(0); 
  44.         } 
  45.         this.order = order; 
  46.         root = new Node(true, true); 
  47.         head = root; 
  48.     } 
  49.     //測試
  50.     publicstaticvoid main(String[] args) { 
  51.         BplusTree tree = new BplusTree(6); 
  52.         Random random = new Random(); 
  53.         long current = System.currentTimeMillis(); 
  54.         for (int j = 0; j < 100000; j++) { 
  55.             for (int i = 0; i < 100; i++) { 
  56.                 int randomNumber = random.nextInt(1000); 
  57.                 tree.insertOrUpdate(randomNumber, randomNumber); 
  58.             } 
  59.             for (int i = 0; i < 100; i++) { 
  60.                 int randomNumber = random.nextInt(1000); 
  61.                 tree.remove(randomNumber); 
  62.             } 
  63.         } 
  64.         long duration = System.currentTimeMillis() - current; 
  65.         System.out.println("time elpsed for duration: " + duration); 
  66.         int search = 80
  67.         System.out.print(tree.get(search)); 
  68.     } 
package com.meidusa.test;

import java.util.Random;

public class BplusTree implements B {
	
	/** 根節點 */
	protected Node root;
	
	/** 階數,M值 */
	protected int order;
	
	/** 葉子節點的連結串列頭*/
	protected Node head;
	
	public Node getHead() {
		return head;
	}

	public void setHead(Node head) {
		this.head = head;
	}

	public Node getRoot() {
		return root;
	}

	public void setRoot(Node root) {
		this.root = root;
	}

	public int getOrder() {
		return order;
	}

	public void setOrder(int order) {
		this.order = order;
	}

	@Override
	public Object get(Comparable key) {
		return root.get(key);
	}

	@Override
	public void remove(Comparable key) {
		root.remove(key, this);

	}

	@Override
	public void insertOrUpdate(Comparable key, Object obj) {
		root.insertOrUpdate(key, obj, this);

	}
	
	public BplusTree(int order){
		if (order < 3) {
			System.out.print("order must be greater than 2");
			System.exit(0);
		}
		this.order = order;
		root = new Node(true, true);
		head = root;
	}
	
	//測試
	public static void main(String[] args) {
		BplusTree tree = new BplusTree(6);
		Random random = new Random();
		long current = System.currentTimeMillis();
		for (int j = 0; j < 100000; j++) {
			for (int i = 0; i < 100; i++) {
				int randomNumber = random.nextInt(1000);
				tree.insertOrUpdate(randomNumber, randomNumber);
			}

			for (int i = 0; i < 100; i++) {
				int randomNumber = random.nextInt(1000);
				tree.remove(randomNumber);
			}
		}

		long duration = System.currentTimeMillis() - current;
		System.out.println("time elpsed for duration: " + duration);
		int search = 80;
		System.out.print(tree.get(search));
	}

}
節點: Java程式碼 複製程式碼 收藏程式碼
  1. package com.meidusa.test; 
  2. import java.util.AbstractMap.SimpleEntry; 
  3. import java.util.ArrayList; 
  4. import java.util.List; 
  5. import java.util.Map.Entry; 
  6. publicclass Node { 
  7.     /** 是否為葉子節點 */
  8.     protectedboolean isLeaf; 
  9.     /** 是否為根節點*/
  10.     protectedboolean isRoot; 
  11.     /** 父節點 */
  12.     protected Node parent; 
  13.     /** 葉節點的前節點*/
  14.     protected Node previous; 
  15.     /** 葉節點的後節點*/
  16.     protected Node next;     
  17.     /** 節點的關鍵字 */
  18.     protected List<Entry<Comparable, Object>> entries; 
  19.     /** 子節點 */
  20.     protected List<Node> children; 
  21.     public Node(boolean isLeaf) { 
  22.         this.isLeaf = isLeaf; 
  23.         entries = new ArrayList<Entry<Comparable, Object>>(); 
  24.         if (!isLeaf) { 
  25.             children = new ArrayList<Node>(); 
  26.         } 
  27.     } 
  28.     public Node(boolean isLeaf, boolean isRoot) { 
  29.         this(isLeaf); 
  30.         this.isRoot = isRoot; 
  31.     } 
  32.     public Object get(Comparable key) { 
  33.         //如果是葉子節點
  34.         if (isLeaf) { 
  35.             for (Entry<Comparable, Object> entry : entries) { 
  36.                 if (entry.getKey().compareTo(key) == 0) { 
  37.                     //返回找到的物件
  38.                     return entry.getValue(); 
  39.                 } 
  40.             } 
  41.             //未找到所要查詢的物件
  42.             returnnull
  43.         //如果不是葉子節點
  44.         }else
  45.             //如果key小於等於節點最左邊的key,沿第一個子節點繼續搜尋
  46.             if (key.compareTo(entries.get(0).getKey()) <= 0) { 
  47.                 return children.get(0).get(key); 
  48.             //如果key大於節點最右邊的key,沿最後一個子節點繼續搜尋
  49.             }elseif (key.compareTo(entries.get(entries.size()-1).getKey()) >= 0) { 
  50.                 return children.get(children.size()-1).get(key); 
  51.             //否則沿比key大的前一個子節點繼續搜尋
  52.             }else
  53.                 for (int i = 0; i < entries.size(); i++) { 
  54.                     if (entries.get(i).getKey().compareTo(key) <= 0 && entries.get(i+1).getKey().compareTo(key) > 0) { 
  55.                         return children.get(i).get(key); 
  56.                     } 
  57.                 }    
  58.             } 
  59.         } 
  60.         returnnull
  61.     } 
  62.     publicvoid insertOrUpdate(Comparable key, Object obj, BplusTree tree){ 
  63.         //如果是葉子節點
  64.         if (isLeaf){ 
  65.             //不需要分裂,直接插入或更新
  66.             if (contains(key) || entries.size() < tree.getOrder()){ 
  67.                 insertOrUpdate(key, obj); 
  68.                 if (parent != null) { 
  69.                     //更新父節點
  70.                     parent.updateInsert(tree); 
  71.                 } 
  72.             //需要分裂 
  73.             }else
  74.                 //分裂成左右兩個節點
  75.                 Node left = new Node(true); 
  76.                 Node right = new Node(true); 
  77.                 //設定連結
  78.                 if (previous != null){ 
  79.                     previous.setNext(left); 
  80.                     left.setPrevious(previous); 
  81.                 } 
  82.                 if (next != null) { 
  83.                     next.setPrevious(right); 
  84.                     right.setNext(next); 
  85.                 } 
  86.                 if (previous == null){ 
  87.                     tree.setHead(left); 
  88.                 } 
  89.                 left.setNext(right); 
  90.                 right.setPrevious(left); 
  91.                 previous = null
  92.                 next = null
  93.                 //左右兩個節點關鍵字長度
  94.                 int leftSize = (tree.getOrder() + 1) / 2 + (tree.getOrder() + 1) % 2;  
  95.                 int rightSize = (tree.getOrder() + 1) / 2
  96.                 //複製原節點關鍵字到分裂出來的新節點
  97.                 insertOrUpdate(key, obj); 
  98.                 for (int i = 0; i < leftSize; i++){ 
  99.                     left.getEntries().add(entries.get(i)); 
  100.                 } 
  101.                 for (int i = 0; i < rightSize; i++){ 
  102.                     right.getEntries().add(entries.get(leftSize + i)); 
  103.                 } 
  104.                 //如果不是根節點
  105.                 if (parent != null) { 
  106.                     //調整父子節點關係
  107.                     int index = parent.getChildren().indexOf(this); 
  108.                     parent.getChildren().remove(this); 
  109.                     left.setParent(parent); 
  110.                     right.setParent(parent); 
  111.                     parent.getChildren().add(index,left); 
  112.                     parent.getChildren().add(index + 1, right); 
  113.                     setEntries(null); 
  114.                     setChildren(null); 
  115.                     //父節點插入或更新關鍵字
  116.                     parent.updateInsert(tree); 
  117.                     setParent(null); 
  118.                 //如果是根節點   
  119.                 }else
  120.                     isRoot = false
  121.                     Node parent = new Node(false, true); 
  122.                     tree.setRoot(parent); 
  123.                     left.setParent(parent); 
  124.                     right.setParent(parent); 
  125.                     parent.getChildren().add(left); 
  126.                     parent.getChildren().add(right); 
  127.                     setEntries(null); 
  128.                     setChildren(null); 
  129.                     //更新根節點
  130.                     parent.updateInsert(tree); 
  131.                 } 
  132.             } 
  133.         //如果不是葉子節點
  134.         }else
  135.             //如果key小於等於節點最左邊的key,沿第一個子節點繼續搜尋
  136.             if (key.compareTo(entries.get(0).getKey()) <= 0) { 
  137.                 children.get(0).insertOrUpdate(key, obj, tree); 
  138.             //如果key大於節點最右邊的key,沿最後一個子節點繼續搜尋
  139.             }elseif (key.compareTo(entries.get(entries.size()-1).getKey()) >= 0) { 
  140.                 children.get(children.size()-1).insertOrUpdate(key, obj, tree); 
  141.             //否則沿比key大的前一個子節點繼續搜尋
  142.             }else
  143.                 for (int i = 0; i < entries.size(); i++) { 
  144.                     if (entries.get(i).getKey().compareTo(key) <= 0 && entries.get(i+1).getKey().compareTo(key) > 0) { 
  145.                         children.get(i).insertOrUpdate(key, obj, tree); 
  146.                         break
  147.                     } 
  148.                 }    
  149.             } 
  150.         } 
  151.     } 
  152.     /** 插入節點後中間節點的更新 */
  153.     protectedvoid updateInsert(BplusTree tree){ 
  154.         validate(this, tree); 
  155.         //如果子節點數超出階數,則需要分裂該節點  
  156.         if (children.size() > tree.getOrder()) { 
  157.             //分裂成左右兩個節點
  158.             Node left = new Node(false); 
  159.             Node right = new Node(false); 
  160.             //左右兩個節點關鍵字長度
  161.             int leftSize = (tree.getOrder() + 1) / 2 + (tree.getOrder() + 1) % 2
  162.             int rightSize = (tree.getOrder() + 1) / 2
  163.             //複製子節點到分裂出來的新節點,並更新關鍵字
  164.             for (int i = 0; i < leftSize; i++){ 
  165.                 left.getChildren().add(children.get(i)); 
  166.                 left.getEntries().add(new SimpleEntry(children.get(i).getEntries().get(0).getKey(), null)); 
  167.                 children.get(i).setParent(left); 
  168.             } 
  169.             for (int i = 0; i < rightSize; i++){ 
  170.                 right.getChildren().add(children.get(leftSize + i)); 
  171.                 right.getEntries().add(new SimpleEntry(children.get(leftSize + i).getEntries().get(0).getKey(), null)); 
  172.                 children.get(leftSize + i).setParent(right); 
  173.             } 
  174.             //如果不是根節點
  175.             if (parent != null) { 
  176.                 //調整父子節點關係
  177.                 int index = parent.getChildren().indexOf(this); 
  178.                 parent.getChildren().remove(this); 
  179.                 left.setParent(parent); 
  180.                 right.setParent(parent); 
  181.                 parent.getChildren().add(index,left); 
  182.                 parent.getChildren().add(index + 1, right); 
  183.                 setEntries(null); 
  184.                 setChildren(null); 
  185.                 //父節點更新關鍵字
  186.                 parent.updateInsert(tree); 
  187.                 setParent(null); 
  188.             //如果是根節點   
  189.             }else
  190.                 isRoot = false
  191.                 Node parent = new Node(false, true); 
  192.                 tree.setRoot(parent); 
  193.                 left.setParent(parent); 
  194.                 right.setParent(parent); 
  195.                 parent.getChildren().add(left); 
  196.                 parent.getChildren().add(right); 
  197.                 setEntries(null); 
  198.                 setChildren(null); 
  199.                 //更新根節點
  200.                 parent.updateInsert(tree); 
  201.             } 
  202.         } 
  203.     } 
  204.     /** 調整節點關鍵字*/
  205.     protectedstaticvoid validate(Node node, BplusTree tree) { 
  206.         // 如果關鍵字個數與子節點個數相同
  207.         if (node.getEntries().size() == node.getChildren().size()) { 
  208.             for (int i = 0; i < node.getEntries().size(); i++) { 
  209.                 Comparable key = node.getChildren().get(i).getEntries().get(0).getKey(); 
  210.                 if (node.getEntries().get(i).getKey().compareTo(key) != 0) { 
  211.                     node.getEntries().remove(i); 
  212.                     node.getEntries().add(i, new SimpleEntry(key, null)); 
  213.                     if(!node.isRoot()){ 
  214.                         validate(node.getParent(), tree); 
  215.                     } 
  216.                 } 
  217.             } 
  218.             // 如果子節點數不等於關鍵字個數但仍大於M / 2並且小於M,並且大於2
  219.         } elseif (node.isRoot() && node.getChildren().size() >= 2
  220.                 ||node.getChildren().size() >= tree.getOrder() / 2
  221.                 && node.getChildren().size() <= tree.getOrder() 
  222.                 && node.getChildren().size() >= 2) { 
  223.             node.getEntries().clear(); 
  224.             for (int i = 0; i < node.getChildren().size(); i++) { 
  225.                 Comparable key = node.getChildren().get(i).getEntries().get(0).getKey(); 
  226.                 node.getEntries().add(new SimpleEntry(key, null)); 
  227.                 if (!node.isRoot()) { 
  228.                     validate(node.getParent(), tree); 
  229.                 } 
  230.             } 
  231.         } 
  232.     } 
  233.     /** 刪除節點後中間節點的更新*/
  234.     protectedvoid updateRemove(BplusTree tree) { 
  235.         validate(this, tree); 
  236.         // 如果子節點數小於M / 2或者小於2,則需要合併節點
  237.         if (children.size() < tree.getOrder() / 2 || children.size() < 2) { 
  238.             if (isRoot) { 
  239.                 // 如果是根節點並且子節點數大於等於2,OK
  240.                 if (children.size() >= 2) { 
  241.                     return
  242.                 // 否則與子節點合併
  243.                 } else
  244.                     Node root = children.get(0); 
  245.                     tree.setRoot(root); 
  246.                     root.setParent(null); 
  247.                     root.setRoot(true); 
  248.                     setEntries(null); 
  249.                     setChildren(null); 
  250.                 } 
  251.             } else
  252.                 //計算前後節點
  253.                 int currIdx = parent.getChildren().indexOf(this); 
  254.                 int prevIdx = currIdx - 1
  255.                 int nextIdx = currIdx + 1
  256.                 Node previous = null, next = null
  257.                 if (prevIdx >= 0) { 
  258.                     previous = parent.getChildren().get(prevIdx); 
  259.                 } 
  260.                 if (nextIdx < parent.getChildren().size()) { 
  261.                     next = parent.getChildren().get(nextIdx); 
  262.                 } 
  263.                 // 如果前節點子節點數大於M / 2並且大於2,則從其處借補
  264.                 if (previous != null
  265.                         && previous.getChildren().size() > tree.getOrder() / 2
  266.                         && previous.getChildren().size() > 2) { 
  267.                     //前葉子節點末尾節點新增到首位
  268.                     int idx = previous.getChildren().size() - 1
  269.                     Node borrow = previous.getChildren().get(idx); 
  270.                     previous.getChildren().remove(idx); 
  271.                     borrow.setParent(this); 
  272.                     children.add(0, borrow); 
  273.                     validate(previous, tree); 
  274.                     validate(this, tree); 
  275.                     parent.updateRemove(tree); 
  276.                 // 如果後節點子節點數大於M / 2並且大於2,則從其處借補
  277.                 } elseif (next != null
  278.                         && next.getChildren().size() > tree.getOrder() / 2
  279.                         && next.getChildren().size() > 2) { 
  280.                     //後葉子節點首位新增到末尾
  281.                     Node borrow = next.getChildren().get(0); 
  282.                     next.getChildren().remove(0); 
  283.                     borrow.setParent(this); 
  284.                     children.add(borrow); 
  285.                     validate(next, tree); 
  286.                     validate(this, tree); 
  287.                     parent.updateRemove(tree); 
  288.                 // 否則需要合併節點
  289.                 } else
  290.                     // 同前面節點合併
  291.                     if (previous != null
  292.                             && (previous.getChildren().size() <= tree.getOrder() / 2 || previous.getChildren().size() <= 2)) { 
  293.                         for (int i = previous.getChildren().size() - 1; i >= 0; i--) { 
  294.                             Node child = previous.getChildren().get(i); 
  295.                             children.add(0, child); 
  296.                             child.setParent(this); 
  297.                         } 
  298.                         previous.setChildren(null); 
  299.                         previous.setEntries(null); 
  300.                         previous.setParent(null); 
  301.                         parent.getChildren().remove(previous); 
  302.                         validate(this, tree); 
  303.                         parent.updateRemove(tree); 
  304.                     // 同後面節點合併
  305.                     } elseif (next != null
  306.                             && (next.getChildren().size() <= tree.getOrder() / 2 || next.getChildren().size() <= 2)) { 
  307.                         for (int i = 0; i < next.getChildren().size(); i++) { 
  308.                             Node child = next.getChildren().get(i); 
  309.                             children.add(child); 
  310.                             child.setParent(this); 
  311.                         } 
  312.                         next.setChildren(null); 
  313.                         next.setEntries(null); 
  314.                         next.setParent(null); 
  315.                         parent.getChildren().remove(next); 
  316.                         validate(this, tree); 
  317.                         parent.updateRemove(tree); 
  318.                     } 
  319.                 } 
  320.             } 
  321.         } 
  322.     } 
  323.     publicvoid remove(Comparable key, BplusTree tree){ 
  324.         //如果是葉子節點
  325.         if (isLeaf){ 
  326.             //如果不包含該關鍵字,則直接返回
  327.             if (!contains(key)){ 
  328.                 return
  329.             } 
  330.             //如果既是葉子節點又是跟節點,直接刪除
  331.             if (isRoot) { 
  332.                 remove(key); 
  333.             }else
  334.                 //如果關鍵字數大於M / 2,直接刪除
  335.                 if (entries.size() > tree.getOrder() / 2 && entries.size() > 2) { 
  336.                     remove(key); 
  337.                 }else
  338.                     //如果自身關鍵字數小於M / 2,並且前節點關鍵字數大於M / 2,則從其處借補
  339.                     if (previous != null
  340.                             && previous.getEntries().size() > tree.getOrder() / 2
  341.                             && previous.getEntries().size() > 2
  342.                             && previous.getParent() == parent) { 
  343.                         int size = previous.getEntries().size(); 
  344.                         Entry<Comparable, Object> entry = previous.getEntries().get(size - 1); 
  345.                         previous.getEntries().remove(entry); 
  346.                         //新增到首位
  347.                         entries.add(0, entry); 
  348.                         remove(key); 
  349.                     //如果自身關鍵字數小於M / 2,並且後節點關鍵字數大於M / 2,則從其處借補  
  350.                     }elseif (next != null
  351.                             && next.getEntries().size() > tree.getOrder() / 2
  352.                             && next.getEntries().size() > 2
  353.                             && next.getParent() == parent) { 
  354.                         Entry<Comparable, Object> entry = next.getEntries().get(0); 
  355.                         next.getEntries().remove(entry); 
  356.                         //新增到末尾
  357.                         entries.add(entry); 
  358.                         remove(key); 
  359.                     //否則需要合併葉子節點   
  360.                     }else
  361.                         //同前面節點合併
  362.                         if (previous != null
  363.                                 && (previous.getEntries().size() <= tree.getOrder() / 2 || previous.getEntries().size() <= 2
  364.                                 && previous.getParent() == parent) { 
  365.                             for (int i = previous.getEntries().size() - 1; i >=0; i--) { 
  366.                                 //從末尾開始新增到首位
  367.                                 entries.add(0, previous.getEntries().get(i)); 
  368.                             } 
  369.                             remove(key); 
  370.                             previous.setParent(null); 
  371.                             previous.setEntries(null); 
  372.                             parent.getChildren().remove(previous); 
  373.                             //更新連結串列
  374.                             if (previous.getPrevious() != null) { 
  375.                                 Node temp = previous; 
  376.                                 temp.getPrevious().setNext(this); 
  377.                                 previous = temp.getPrevious(); 
  378.                                 temp.setPrevious(null); 
  379.                                 temp.setNext(null);                          
  380.                             }else
  381.                                 tree.setHead(this); 
  382.                                 previous.setNext(null); 
  383.                                 previous = null
  384.                             } 
  385.                         //同後面節點合併  
  386.                         }else if(next != null
  387.                                 && (next.getEntries().size() <= tree.getOrder() / 2 || next.getEntries().size() <= 2
  388.                                 && next.getParent() == parent){ 
  389.                             for (int i = 0; i < next.getEntries().size(); i++) { 
  390.                                 //從首位開始新增到末尾
  391.                                 entries.add(next.getEntries().get(i)); 
  392.                             } 
  393.                             remove(key); 
  394.                             next.setParent(null); 
  395.                             next.setEntries(null); 
  396.                             parent.getChildren().remove(next); 
  397.                             //更新連結串列
  398.                             if (next.getNext() != null) { 
  399.                                 Node temp = next; 
  400.                                 temp.getNext().setPrevious(this); 
  401.                                 next = temp.getNext(); 
  402.                                 temp.setPrevious(null); 
  403.                                 temp.setNext(null); 
  404.                             }else
  405.                                 next.setPrevious(null); 
  406.                                 next = null
  407.                             } 
  408.                         } 
  409.                     } 
  410.                 } 
  411.                 parent.updateRemove(tree); 
  412.             } 
  413.         //如果不是葉子節點 
  414.         }else
  415.             //如果key小於等於節點最左邊的key,沿第一個子節點繼續搜尋
  416.             if (key.compareTo(entries.get(0).getKey()) <= 0) { 
  417.                 children.get(0).remove(key, tree); 
  418.             //如果key大於節點最右邊的key,沿最後一個子節點繼續搜尋
  419.             }elseif (key.compareTo(entries.get(entries.size()-