package cn.hit.sqlLab2;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* B树索引
*
*/
public class BtreeIndex {
private static int cnt = 7; //每个B树节点的键值个数
private static int t = (cnt + 1) / 2;
private static BtreeNode root = null; //根节点
private static BufferedReader in = null;
private static BufferedWriter out = null;
private static int outnumber = 0;
public static void run() {
// 随机生成1000000条记录并存入文本文件
// Generator.generator();
// System.out.println(Generator.messages.size());
long startTime = System.nanoTime();
FileWriter write = null;
try {
write = new FileWriter(new File("res/output-" + cnt + ".txt"));
out = new BufferedWriter(write);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
List messages = new ArrayList();
FileReader reader;
try {
reader = new FileReader(new File("res/input.txt"));
in = new BufferedReader(reader);
String inLine = null;
while ((inLine = in.readLine()) != null) {
Message message = new Message(Integer.parseInt(inLine.split(" ")[0]), inLine.split(" ")[1]);
messages.add(message);
}
System.out.println("messages number:"+messages.size());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
BtreeIndex.buildBtree(messages);
System.out.println("build success!");
printNode(root);
System.out.println("outnumber:" + outnumber);
long endTime = System.nanoTime();
long duration = (endTime - startTime) / 1000000;
try {
out.write("<<<<<>>>>>");
System.out.println("<<<<<>>>>>");
} catch (IOException e) {
e.printStackTrace();
}
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
// 对每条记录执行查找和删除操作
boolean delete = true;
for (Message message : messages) {
// System.out.print(message.getNum());
if (!root.isLeaf() && root.getEntryNumber() == 1
&& root.getChildren().get(0).getEntryNumber() < t
&& root.getChildren().get(1).getEntryNumber() < t) {
root =
merge(root.getChildren().get(0), root.getChildren().get(1), root.getEntries().get(0));
}
/*
* if (search(message.getNum()) != null) {
* System.out.print(":find it!");
* } else {
* System.out.print(":not find it.!");
* }
*/
boolean deleteone = delete(root, message.getNum());
// System.out.println(" delete" + deleteone + "!");
if (deleteone == false) {
delete = false;
}
if (!delete) {
return;
}
}
System.out.println("all delete!");
try {
write = new FileWriter(new File("res/delete-output" + ".txt"));
out = new BufferedWriter(write);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
outnumber = 0;
printNode(root);
System.out.println("outnumber:" + outnumber);
System.out.println(delete);
try {
in.close();
out.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
private static BtreeNode merge(BtreeNode leftNode, BtreeNode rightNode, Entry middle) {
leftNode.addEntry(middle);
for (int i = 0; i < rightNode.getEntryNumber(); i++) {
Entry entry = rightNode.getEntries().get(i);
leftNode.addEntry(entry);
}
BtreeNode childNode = null;
for (int i = 0; i < rightNode.getChildrenNumber(); i++) {
childNode = rightNode.getChildren().get(i);
leftNode.addChild(childNode);
}
return leftNode;
}
/**
* build the B-tree index
*
* @param messages
*/
public static void buildBtree(List messages) {
root = new BtreeNode();
for (Message message : messages) {
insert(message, root);
}
}
private static void printNode(BtreeNode node) {
if (node.isLeaf()) {
for (int i = 0; i < node.getEntryNumber(); i++) {
Entry entry = node.getEntries().get(i);
try {
out.write(entry.key + " " + entry.value);
out.newLine();
outnumber++;
} catch (IOException e) {
e.printStackTrace();
}
}
} else {
for (int i = 0; i < node.getChildrenNumber(); i++) {
printNode(node.getChildren().get(i));
if (node.getEntryNumber() <= i) continue;
Entry entry = node.getEntries().get(i);
try {
out.write(entry.key + " " + entry.value);
out.newLine();
outnumber++;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* insert a new node in 'node'
*
* @param message
* @param node
*/
private static void insert(Message message, BtreeNode node) {
// node是叶子节点
if (node.isLeaf()) {
node.addEntry(new Entry(message.getNum(), message.getString()));
// node空间未满
if (node.getEntryNumber() <= cnt) {
return;
} else {
// node空间满了,需要分裂
balence(node);
}
} else {
// node不是叶子节点,插入合适的子节点中
List entries = node.getEntries();
boolean flag = false;
for (int i = 0; i < entries.size(); i++) {
int key = entries.get(i).key;
if (message.getNum() <= key) {
insert(message, node.getChildren().get(i));
flag = true;
break;
}
}
if (!flag) {
insert(message, node.getChildren().get(node.getEntryNumber()));
}
}
}
/**
* the node is overflow,needs split
*
* @param node
*/
private static void balence(BtreeNode node) {
int middleIndex = (cnt) / 2;
List entries = node.getEntries();
// 分裂;
BtreeNode fatherNode = new BtreeNode();
BtreeNode leftChild = new BtreeNode();
BtreeNode rightChild = new BtreeNode();
for (int i = 0; i < middleIndex; i++) {
leftChild.addEntry(entries.get(i));
if (i < node.getChildrenNumber()) {
leftChild.addChild(node.getChildren().get(i));
}
}
if (middleIndex < node.getChildrenNumber()) {
leftChild.addChild(node.getChildren().get(middleIndex));
}
for (int i = middleIndex + 1; i <= cnt; i++) {
rightChild.addEntry(entries.get(i));
if (i < node.getChildrenNumber()) {
rightChild.addChild(node.getChildren().get(i));
}
}
if (cnt + 1 < node.getChildrenNumber()) {
rightChild.addChild(node.getChildren().get(cnt + 1));
}
// node有父节点,上移至父节点
if (node.getFather() != null) {
fatherNode = node.getFather();
fatherNode.getChildren().remove(node);
fatherNode.addEntry(entries.get(middleIndex));
fatherNode.addChild(leftChild);
fatherNode.addChild(rightChild);
} else {// node无父节点,更新root
fatherNode.addEntry(entries.get(middleIndex));
fatherNode.addChild(leftChild);
fatherNode.addChild(rightChild);
root = fatherNode;
}
// 父节点溢出,继续分裂
if (fatherNode.getEntryNumber() <= cnt) {
return;
} else {
balence(fatherNode);
}
}
/**
* search in the B-tree
*
* @param key
* @return
*/
private static List search(Integer key) {
return search(root, key);
}
/**
* search in one node
*
* @param node
* @param key
* @return
*/
private static List search(BtreeNode node, Integer key) {
SearchResult result = node.searchKey(key);
if (result.isExist()) {
return result.getValue();
} else {
if (node.isLeaf()) {
return null;
} else {
boolean flag = false;
List entries = node.getEntries();
for (int i = 0; i < entries.size(); i++) {
if (key < entries.get(i).key) {
flag = true;
return search(node.getChildren().get(i), key);
}
}
if (!flag) {
return search(node.getChildren().get(node.getChildrenNumber() - 1), key);
}
}
}
return null;
}
/**
* 找到以node为根节点的子树里最大的一项
*
* @param node
* @return the max entry found
*/
private static Entry findAndDeletePrev(BtreeNode node) {
Entry entry = null;
while (!node.isLeaf()) {
node = node.getChildren().get(node.getChildrenNumber() - 1);
}
entry = node.getEntries().get(node.getEntryNumber() - 1);
// node.getEntries().remove(node.getEntryNumber()-1);
return entry;
}
/**
* 找到以node为根节点的子树里最小的一项
*
* @param node
* @return the min entry found
*/
private static Entry findAndDeleteNext(BtreeNode node) {
Entry entry = null;
while (!node.isLeaf()) {
node = node.getChildren().get(0);
}
entry = node.getEntries().get(0);
// node.getEntries().remove(0);
return entry;
}
private static boolean delete(BtreeNode node, Integer key) {
// 1.待删除的key在叶子节点,直接删除就好
if (node.isLeaf()) {
List entries = node.getEntries();
for (int i = 0; i < entries.size(); i++) {
Entry entry = entries.get(i);
if (entry.key == key) {
node.getEntries().remove(entry);
return true;
}
}
return false;
}
// x不是叶子节点
boolean isExist = false;
int position = node.getEntryNumber();
for (int i = 0; i < node.getEntryNumber(); i++) {
Entry entry = node.getEntries().get(i);
if (entry.key > key) {
position = i;
break;
}
// 2.要删除的key在内部节点x
if (entry.key == key) {
isExist = true;
BtreeNode leftChildNode = node.getChildren().get(i);
BtreeNode rightChildNode = node.getChildren().get(i + 1);
// 2.(a)如果x的左分支结点y至少包含t个关键字,则找出以y为根的子树的最右的关键字prev,并替换target,并在y中递归删除prev。
if (leftChildNode.getEntryNumber() >= t) {
Entry prev = findAndDeletePrev(leftChildNode);
if (prev == null) {
return false;
}
node.getEntries().set(i, prev);
return delete(leftChildNode, prev.key);
}
// 2.(b) 如果x的右分支结点z至少包含t个关键字,则找出以z为根的子树的最左的关键字next,并替换target,并在z中递归删除next.
if (rightChildNode.getEntryNumber() >= t) {
Entry next = findAndDeleteNext(rightChildNode);
if (next == null) {
return false;
}
node.getEntries().set(i, next);
return delete(rightChildNode, next.key);
}
// 2.(c) 否则,如果y和z都只有t-1个关键字,则将target与z合并到y中,使得y有2t-1个关键字,再从y中递归删除target.
node.getEntries().remove(entry);
node.getChildren().remove(rightChildNode);
leftChildNode = merge(leftChildNode, rightChildNode, entry);
return delete(leftChildNode, key);
}
}
// (3) 如果关键字不在内部结点x中,则必然在x的某个分支结点p[i]为根的子树中,
// 执行3a、3b或者3c以保证我们降至一个包含至少t个关键字的结点,然后通过对x的某个合适的子结点递归而结束。
if (!isExist) {
BtreeNode childNode = node.getChildren().get(position); // p[i];
if (childNode.getEntryNumber() >= t) {
return delete(childNode, key);
}
BtreeNode leftChildNode = null;
BtreeNode rightChildNode = null;
if (position > 0) {
leftChildNode = node.getChildren().get(position - 1);
}
if (position < node.getChildrenNumber() - 1) {
rightChildNode = node.getChildren().get(position + 1);
}
// (a) 如果p[i-1]拥有至少t个关键字,则将x[i-1]的关键字降至p[i]中,将p[i-1]的最大结点上升至x中。
if (leftChildNode != null && leftChildNode.getEntryNumber() >= t) {
Entry x = node.getEntries().get(position - 1);
Entry y = leftChildNode.getEntries().get(leftChildNode.getEntryNumber() - 1);
node.getEntries().remove(x);
leftChildNode.getEntries().remove(y);
node.addEntry(y);
childNode.addEntry(x);
if (leftChildNode.getChildrenNumber() > 0) {
BtreeNode changeChild =
leftChildNode.getChildren().get(leftChildNode.getChildrenNumber() - 1);
leftChildNode.getChildren().remove(leftChildNode.getChildrenNumber() - 1);
childNode.addChild(changeChild);
}
return delete(childNode, key);
}
// (b) 如果p[i+1]拥有至少t个关键字,则将x[i]的关键字降至p[i]中,将p[i+1]的最小关键字上升至x中。
if (rightChildNode != null && rightChildNode.getEntryNumber() >= t) {
Entry x = node.getEntries().get(position);
Entry y = rightChildNode.getEntries().get(0);
node.getEntries().remove(x);
rightChildNode.getEntries().remove(y);
node.addEntry(y);
childNode.addEntry(x);
if (rightChildNode.getChildrenNumber() > 0) {
BtreeNode changeChild = rightChildNode.getChildren().get(0);
rightChildNode.getChildren().remove(0);
childNode.addChild(changeChild);
}
return delete(childNode, key);
}
// (c) 否则将p[i]与其中一个兄弟合并,将x[i-1]或x[i]的关键字降至合并的结点中,成为中间关键字。
if (leftChildNode != null) {
Entry x = node.getEntries().get(position - 1);
node.getEntries().remove(x);
leftChildNode = merge(leftChildNode, childNode, x);
node.getChildren().remove(childNode);
return delete(leftChildNode, key);
}
if (rightChildNode != null && leftChildNode == null) {
Entry x = node.getEntries().get(position);
node.getEntries().remove(x);
childNode = merge(childNode, rightChildNode, x);
node.getChildren().remove(rightChildNode);
return delete(childNode, key);
}
}
return false;
}
}