B+樹的Java實現

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實現:

接口:

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+樹:
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));
	}

}
 
節點:
package com.meidusa.test;

import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;

public class Node {
	
	/** 是否爲葉子節點 */
	protected boolean isLeaf;
	
	/** 是否爲根節點*/
	protected boolean isRoot;

	/** 父節點 */
	protected Node parent;
	
	/** 葉節點的前節點*/
	protected Node previous;
	
	/** 葉節點的後節點*/
	protected Node next;	
	
	/** 節點的關鍵字 */
	protected List<Entry<Comparable, Object>> entries;
	
	/** 子節點 */
	protected List<Node> children;
	
	public Node(boolean isLeaf) {
		this.isLeaf = isLeaf;
		entries = new ArrayList<Entry<Comparable, Object>>();
		
		if (!isLeaf) {
			children = new ArrayList<Node>();
		}
	}

	public Node(boolean isLeaf, boolean isRoot) {
		this(isLeaf);
		this.isRoot = isRoot;
	}
	
	public Object get(Comparable key) {
		
		//如果是葉子節點
		if (isLeaf) {
			for (Entry<Comparable, Object> entry : entries) {
				if (entry.getKey().compareTo(key) == 0) {
					//返回找到的對象
					return entry.getValue();
				}
			}
			//未找到所要查詢的對象
			return null;
			
		//如果不是葉子節點
		}else {
			//如果key小於等於節點最左邊的key,沿第一個子節點繼續搜索
			if (key.compareTo(entries.get(0).getKey()) <= 0) {
				return children.get(0).get(key);
			//如果key大於節點最右邊的key,沿最後一個子節點繼續搜索
			}else if (key.compareTo(entries.get(entries.size()-1).getKey()) >= 0) {
				return children.get(children.size()-1).get(key);
			//否則沿比key大的前一個子節點繼續搜索
			}else {
				for (int i = 0; i < entries.size(); i++) {
					if (entries.get(i).getKey().compareTo(key) <= 0 && entries.get(i+1).getKey().compareTo(key) > 0) {
						return children.get(i).get(key);
					}
				}	
			}
		}
		
		return null;
	}
	
	public void insertOrUpdate(Comparable key, Object obj, BplusTree tree){
		//如果是葉子節點
		if (isLeaf){
			//不需要分裂,直接插入或更新
			if (contains(key) || entries.size() < tree.getOrder()){
				insertOrUpdate(key, obj);
				if (parent != null) {
					//更新父節點
					parent.updateInsert(tree);
				}

			//需要分裂	
			}else {
				//分裂成左右兩個節點
				Node left = new Node(true);
				Node right = new Node(true);
				//設置鏈接
				if (previous != null){
					previous.setNext(left);
					left.setPrevious(previous);
				}
				if (next != null) {
					next.setPrevious(right);
					right.setNext(next);
				}
				if (previous == null){
					tree.setHead(left);
				}

				left.setNext(right);
				right.setPrevious(left);
				previous = null;
				next = null;
				
				//左右兩個節點關鍵字長度
				int leftSize = (tree.getOrder() + 1) / 2 + (tree.getOrder() + 1) % 2; 
				int rightSize = (tree.getOrder() + 1) / 2;
				//複製原節點關鍵字到分裂出來的新節點
				insertOrUpdate(key, obj);
				for (int i = 0; i < leftSize; i++){
					left.getEntries().add(entries.get(i));
				}
				for (int i = 0; i < rightSize; i++){
					right.getEntries().add(entries.get(leftSize + i));
				}
				
				//如果不是根節點
				if (parent != null) {
					//調整父子節點關係
					int index = parent.getChildren().indexOf(this);
					parent.getChildren().remove(this);
					left.setParent(parent);
					right.setParent(parent);
					parent.getChildren().add(index,left);
					parent.getChildren().add(index + 1, right);
					setEntries(null);
					setChildren(null);
					
					//父節點插入或更新關鍵字
					parent.updateInsert(tree);
					setParent(null);
				//如果是根節點	
				}else {
					isRoot = false;
					Node parent = new Node(false, true);
					tree.setRoot(parent);
					left.setParent(parent);
					right.setParent(parent);
					parent.getChildren().add(left);
					parent.getChildren().add(right);
					setEntries(null);
					setChildren(null);
					
					//更新根節點
					parent.updateInsert(tree);
				}
				

			}
			
		//如果不是葉子節點
		}else {
			//如果key小於等於節點最左邊的key,沿第一個子節點繼續搜索
			if (key.compareTo(entries.get(0).getKey()) <= 0) {
				children.get(0).insertOrUpdate(key, obj, tree);
			//如果key大於節點最右邊的key,沿最後一個子節點繼續搜索
			}else if (key.compareTo(entries.get(entries.size()-1).getKey()) >= 0) {
				children.get(children.size()-1).insertOrUpdate(key, obj, tree);
			//否則沿比key大的前一個子節點繼續搜索
			}else {
				for (int i = 0; i < entries.size(); i++) {
					if (entries.get(i).getKey().compareTo(key) <= 0 && entries.get(i+1).getKey().compareTo(key) > 0) {
						children.get(i).insertOrUpdate(key, obj, tree);
						break;
					}
				}	
			}
		}
	}
	
	/** 插入節點後中間節點的更新 */
	protected void updateInsert(BplusTree tree){

		validate(this, tree);
		
		//如果子節點數超出階數,則需要分裂該節點	
		if (children.size() > tree.getOrder()) {
			//分裂成左右兩個節點
			Node left = new Node(false);
			Node right = new Node(false);
			//左右兩個節點關鍵字長度
			int leftSize = (tree.getOrder() + 1) / 2 + (tree.getOrder() + 1) % 2;
			int rightSize = (tree.getOrder() + 1) / 2;
			//複製子節點到分裂出來的新節點,並更新關鍵字
			for (int i = 0; i < leftSize; i++){
				left.getChildren().add(children.get(i));
				left.getEntries().add(new SimpleEntry(children.get(i).getEntries().get(0).getKey(), null));
				children.get(i).setParent(left);
			}
			for (int i = 0; i < rightSize; i++){
				right.getChildren().add(children.get(leftSize + i));
				right.getEntries().add(new SimpleEntry(children.get(leftSize + i).getEntries().get(0).getKey(), null));
				children.get(leftSize + i).setParent(right);
			}
			
			//如果不是根節點
			if (parent != null) {
				//調整父子節點關係
				int index = parent.getChildren().indexOf(this);
				parent.getChildren().remove(this);
				left.setParent(parent);
				right.setParent(parent);
				parent.getChildren().add(index,left);
				parent.getChildren().add(index + 1, right);
				setEntries(null);
				setChildren(null);
				
				//父節點更新關鍵字
				parent.updateInsert(tree);
				setParent(null);
			//如果是根節點	
			}else {
				isRoot = false;
				Node parent = new Node(false, true);
				tree.setRoot(parent);
				left.setParent(parent);
				right.setParent(parent);
				parent.getChildren().add(left);
				parent.getChildren().add(right);
				setEntries(null);
				setChildren(null);
				
				//更新根節點
				parent.updateInsert(tree);
			}
		}
	}
	
	/** 調整節點關鍵字*/
	protected static void validate(Node node, BplusTree tree) {
		
		// 如果關鍵字個數與子節點個數相同
		if (node.getEntries().size() == node.getChildren().size()) {
			for (int i = 0; i < node.getEntries().size(); i++) {
				Comparable key = node.getChildren().get(i).getEntries().get(0).getKey();
				if (node.getEntries().get(i).getKey().compareTo(key) != 0) {
					node.getEntries().remove(i);
					node.getEntries().add(i, new SimpleEntry(key, null));
					if(!node.isRoot()){
						validate(node.getParent(), tree);
					}
				}
			}
			// 如果子節點數不等於關鍵字個數但仍大於M / 2並且小於M,並且大於2
		} else if (node.isRoot() && node.getChildren().size() >= 2 
				||node.getChildren().size() >= tree.getOrder() / 2 
				&& node.getChildren().size() <= tree.getOrder()
				&& node.getChildren().size() >= 2) {
			node.getEntries().clear();
			for (int i = 0; i < node.getChildren().size(); i++) {
				Comparable key = node.getChildren().get(i).getEntries().get(0).getKey();
				node.getEntries().add(new SimpleEntry(key, null));
				if (!node.isRoot()) {
					validate(node.getParent(), tree);
				}
			}
		}
	}
	
	/** 刪除節點後中間節點的更新*/
	protected void updateRemove(BplusTree tree) {
		
		validate(this, tree);

		// 如果子節點數小於M / 2或者小於2,則需要合併節點
		if (children.size() < tree.getOrder() / 2 || children.size() < 2) {
			if (isRoot) {
				// 如果是根節點並且子節點數大於等於2,OK
				if (children.size() >= 2) {
					return;
				// 否則與子節點合併
				} else {
					Node root = children.get(0);
					tree.setRoot(root);
					root.setParent(null);
					root.setRoot(true);
					setEntries(null);
					setChildren(null);
				}
			} else {
				//計算前後節點 
				int currIdx = parent.getChildren().indexOf(this);
				int prevIdx = currIdx - 1;
				int nextIdx = currIdx + 1;
				Node previous = null, next = null;
				if (prevIdx >= 0) {
					previous = parent.getChildren().get(prevIdx);
				}
				if (nextIdx < parent.getChildren().size()) {
					next = parent.getChildren().get(nextIdx);
				}
				
				// 如果前節點子節點數大於M / 2並且大於2,則從其處借補
				if (previous != null 
						&& previous.getChildren().size() > tree.getOrder() / 2
						&& previous.getChildren().size() > 2) {
					//前葉子節點末尾節點添加到首位
					int idx = previous.getChildren().size() - 1;
					Node borrow = previous.getChildren().get(idx);
					previous.getChildren().remove(idx);
					borrow.setParent(this);
					children.add(0, borrow);
					validate(previous, tree);
					validate(this, tree);
					parent.updateRemove(tree);
					
				// 如果後節點子節點數大於M / 2並且大於2,則從其處借補
				} else if (next != null	
						&& next.getChildren().size() > tree.getOrder() / 2
						&& next.getChildren().size() > 2) {
					//後葉子節點首位添加到末尾
					Node borrow = next.getChildren().get(0);
					next.getChildren().remove(0);
					borrow.setParent(this);
					children.add(borrow);
					validate(next, tree);
					validate(this, tree);
					parent.updateRemove(tree);
					
				// 否則需要合併節點
				} else {
					// 同前面節點合併
					if (previous != null 
							&& (previous.getChildren().size() <= tree.getOrder() / 2 || previous.getChildren().size() <= 2)) {
						
						for (int i = previous.getChildren().size() - 1; i >= 0; i--) {
							Node child = previous.getChildren().get(i);
							children.add(0, child);
							child.setParent(this);
						}
						previous.setChildren(null);
						previous.setEntries(null);
						previous.setParent(null);
						parent.getChildren().remove(previous);
						validate(this, tree);
						parent.updateRemove(tree);
						
					// 同後面節點合併
					} else if (next != null	
							&& (next.getChildren().size() <= tree.getOrder() / 2 || next.getChildren().size() <= 2)) {

						for (int i = 0; i < next.getChildren().size(); i++) {
							Node child = next.getChildren().get(i);
							children.add(child);
							child.setParent(this);
						}
						next.setChildren(null);
						next.setEntries(null);
						next.setParent(null);
						parent.getChildren().remove(next);
						validate(this, tree);
						parent.updateRemove(tree);
					}
				}
			}
		}
	}
	
	public void remove(Comparable key, BplusTree tree){
		//如果是葉子節點
		if (isLeaf){
			
			//如果不包含該關鍵字,則直接返回
			if (!contains(key)){
				return;
			}
			
			//如果既是葉子節點又是跟節點,直接刪除
			if (isRoot) {
				remove(key);
			}else {
				//如果關鍵字數大於M / 2,直接刪除
				if (entries.size() > tree.getOrder() / 2 && entries.size() > 2) {
					remove(key);
				}else {
					//如果自身關鍵字數小於M / 2,並且前節點關鍵字數大於M / 2,則從其處借補
					if (previous != null 
							&& previous.getEntries().size() > tree.getOrder() / 2
							&& previous.getEntries().size() > 2
							&& previous.getParent() == parent) {
						int size = previous.getEntries().size();
						Entry<Comparable, Object> entry = previous.getEntries().get(size - 1);
						previous.getEntries().remove(entry);
						//添加到首位
						entries.add(0, entry);
						remove(key);
					//如果自身關鍵字數小於M / 2,並且後節點關鍵字數大於M / 2,則從其處借補	
					}else if (next != null 
							&& next.getEntries().size() > tree.getOrder() / 2
							&& next.getEntries().size() > 2
							&& next.getParent() == parent) {
						Entry<Comparable, Object> entry = next.getEntries().get(0);
						next.getEntries().remove(entry);
						//添加到末尾
						entries.add(entry);
						remove(key);
					//否則需要合併葉子節點	
					}else {
						//同前面節點合併
						if (previous != null 
								&& (previous.getEntries().size() <= tree.getOrder() / 2 || previous.getEntries().size() <= 2)
								&& previous.getParent() == parent) {
							for (int i = previous.getEntries().size() - 1; i >=0; i--) {
								//從末尾開始添加到首位
								entries.add(0, previous.getEntries().get(i));
							}
							remove(key);
							previous.setParent(null);
							previous.setEntries(null);
							parent.getChildren().remove(previous);
							//更新鏈表
							if (previous.getPrevious() != null) {
								Node temp = previous;
								temp.getPrevious().setNext(this);
								previous = temp.getPrevious();
								temp.setPrevious(null);
								temp.setNext(null);							
							}else {
								tree.setHead(this);
								previous.setNext(null);
								previous = null;
							}
						//同後面節點合併	
						}else if(next != null 
								&& (next.getEntries().size() <= tree.getOrder() / 2 || next.getEntries().size() <= 2)
								&& next.getParent() == parent){
							for (int i = 0; i < next.getEntries().size(); i++) {
								//從首位開始添加到末尾
								entries.add(next.getEntries().get(i));
							}
							remove(key);
							next.setParent(null);
							next.setEntries(null);
							parent.getChildren().remove(next);
							//更新鏈表
							if (next.getNext() != null) {
								Node temp = next;
								temp.getNext().setPrevious(this);
								next = temp.getNext();
								temp.setPrevious(null);
								temp.setNext(null);
							}else {
								next.setPrevious(null);
								next = null;
							}
						}
					}
				}
				parent.updateRemove(tree);
			}
		//如果不是葉子節點	
		}else {
			//如果key小於等於節點最左邊的key,沿第一個子節點繼續搜索
			if (key.compareTo(entries.get(0).getKey()) <= 0) {
				children.get(0).remove(key, tree);
			//如果key大於節點最右邊的key,沿最後一個子節點繼續搜索
			}else if (key.compareTo(entries.get(entries.size()-1).getKey()) >= 0) {
				children.get(children.size()-1).remove(key, tree);
			//否則沿比key大的前一個子節點繼續搜索
			}else {
				for (int i = 0; i < entries.size(); i++) {
					if (entries.get(i).getKey().compareTo(key) <= 0 && entries.get(i+1).getKey().compareTo(key) > 0) {
						children.get(i).remove(key, tree);
						break;
					}
				}	
			}
		}
	}
	
	/** 判斷當前節點是否包含該關鍵字*/
	protected boolean contains(Comparable key) {
		for (Entry<Comparable, Object> entry : entries) {
			if (entry.getKey().compareTo(key) == 0) {
				return true;
			}
		}
		return false;
	}
	
	/** 插入到當前節點的關鍵字中*/
	protected void insertOrUpdate(Comparable key, Object obj){
		Entry<Comparable, Object> entry = new SimpleEntry<Comparable, Object>(key, obj);
		//如果關鍵字列表長度爲0,則直接插入
		if (entries.size() == 0) {
			entries.add(entry);
			return;
		}
		//否則遍歷列表
		for (int i = 0; i < entries.size(); i++) {
			//如果該關鍵字鍵值已存在,則更新
			if (entries.get(i).getKey().compareTo(key) == 0) {
				entries.get(i).setValue(obj);
				return;
			//否則插入	
			}else if (entries.get(i).getKey().compareTo(key) > 0){
				//插入到鏈首
				if (i == 0) {
					entries.add(0, entry);
					return;
				//插入到中間
				}else {
					entries.add(i, entry);
					return;
				}
			}
		}
		//插入到末尾
		entries.add(entries.size(), entry);
	}
	
	/** 刪除節點*/
	protected void remove(Comparable key){
		int index = -1;
		for (int i = 0; i < entries.size(); i++) {
			if (entries.get(i).getKey().compareTo(key) == 0) {
				index = i;
				break;
			}
		}
		if (index != -1) {
			entries.remove(index);
		}
	}
	
	public Node getPrevious() {
		return previous;
	}

	public void setPrevious(Node previous) {
		this.previous = previous;
	}

	public Node getNext() {
		return next;
	}

	public void setNext(Node next) {
		this.next = next;
	}

	public boolean isLeaf() {
		return isLeaf;
	}

	public void setLeaf(boolean isLeaf) {
		this.isLeaf = isLeaf;
	}

	public Node getParent() {
		return parent;
	}

	public void setParent(Node parent) {
		this.parent = parent;
	}

	public List<Entry<Comparable, Object>> getEntries() {
		return entries;
	}

	public void setEntries(List<Entry<Comparable, Object>> entries) {
		this.entries = entries;
	}

	public List<Node> getChildren() {
		return children;
	}

	public void setChildren(List<Node> children) {
		this.children = children;
	}
	
	public boolean isRoot() {
		return isRoot;
	}

	public void setRoot(boolean isRoot) {
		this.isRoot = isRoot;
	}
	
	public String toString(){
		StringBuilder sb = new StringBuilder();
		sb.append("isRoot: ");
		sb.append(isRoot);
		sb.append(", ");
		sb.append("isLeaf: ");
		sb.append(isLeaf);
		sb.append(", ");
		sb.append("keys: ");
		for (Entry entry : entries){
			sb.append(entry.getKey());
			sb.append(", ");
		}
		sb.append(", ");
		return sb.toString();
		
	}

}
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章