2017/08/29 2-3-4树

来源:互联网 发布:万网域名登陆 编辑:程序博客网 时间:2024/06/04 20:08
public class Tree234 {
public static void main(String[] args) {
Tree234 theTree = new Tree234();
theTree.insert(50);
theTree.insert(40);
theTree.insert(60);
theTree.insert(30);
theTree.insert(70);
theTree.insert(20);
theTree.insert(10);
theTree.displayTree();
}
// 根节点
private Node root = new Node();
// 从树里面搜索是否存在数据项,返回其在其节点的索引值
public int find(int key) {
// 根节点置为当前节点,从当前节点开始寻找
Node current = root;
int childNumber;
while (true) {
// 找到数据项 返回索引值
if((childNumber = current.findItem(key)) != -1)
return childNumber;
// 找到根节点 返回-1
else if(current.isLeaf())
return -1;
else
// 去子节点中寻找是否含有数据项
current = getNextChild(current,key);
}
}
// 往树里面插入一个数据项
public void insert(int key) {
// 根节点置为当前节点,从当前节点开始寻找 插入位置
Node current = root;
DataItem tempItem = new DataItem(key);
while (true) {
// 发现某个节点是满节点,分裂节点
if(current.isFull()){
split(current);
current = current.getParent();
current = getNextChild(current, key);
}
// 一直找到叶节点,插入总是在叶节点进行的
else if(current.isLeaf())
break;
else 
// 把合适的子节点置为当前节点
current = getNextChild(current, key);
}
current.insertItem(tempItem);
}
// 分裂节点
private void split(Node current) {
DataItem itemB,itemC;
Node parent,child2,child3;
int itemIndex;
// 删除当前节点的两个数据项
itemC = current.removeItem();
itemB = current.removeItem();
// 删除当前节点的两个子节点引用
child2 = current.disconnectChild(2);
child3 = current.disconnectChild(3);
// 创建新的右节点
Node newRight = new Node();
if(current == root){
// 当前节点是父节点,创键新的父节点
root = new Node();
parent = root;
root.connectChild(0, current);
}
else
parent = current.getParent();
// 父节点插入B数据项
itemIndex = parent.insertItem(itemB);
// 获取父节点的数据项的数量
int n = parent.getNumItems();
for (int j = n-1; j > itemIndex; j--) {
Node temp = parent.disconnectChild(j);
parent.connectChild(j+1, temp);
}
// 新建右节点作为当前节点的父节点的子节点
parent.connectChild(itemIndex+1, newRight);
// 右节点插入数据项C
newRight.insertItem(itemC);
// 右节点 获得当前节点的两个子节点引用
newRight.connectChild(0, child2);
newRight.connectChild(1, child3);
}
// 找到合适的子节点置为当前节点
private Node getNextChild(Node current, int key) {
int j;
// 取到当前节点的存储数据项的数量,应为1或2
int numItems = current.getNumItems();
for (j = 0; j < numItems; j++) {
// 与每个数据项的值相比较,找到合适位置
if(key < current.getItem(j).dData)
return current.getChild(j);
}
return current.getChild(j);
}
// 从根节点开始展示树的所有数据项
public void displayTree() {
recDisplayTree(root,0,0);
}
// 递归打印树的所有节点
private void recDisplayTree(Node thisNode, int level, int childNumber) {
System.out.print("level = "+level+" child = "+childNumber+" ");
thisNode.displayNode();
// 获取这个节点的数据项的个数
int numItems = thisNode.getNumItems();
for (int j = 0; j < numItems + 1; j++) {
// 获取这个节点的每个子节点
Node nextNode = thisNode.getChild(j);
if(nextNode != null)
// 递归打印子节点
recDisplayTree(nextNode, level+1, j);
else
return;
}
}

}
// 存储数据的类
class DataItem{
// 以存储数字为例
public int dData;
// 初始化赋值
public DataItem (int dd) {
dData = dd;
}
// 打印数据
public void displayItem() {
System.out.print("/"+dData);
}
}
// 节点类
class Node{
// 表示子节点的最大个数
private static final int ORDER = 4;
// 记录这个节点上有多少数据项
private int numItems;
// 指向父节点的引用
private Node parent;
// 存储子节点的数据,最大为4
private Node[] childArray = new Node[ORDER];
// 记录这个节点存储数据的数量,最大为3
private DataItem[] itemArray = new DataItem[ORDER-1];

// 添加一个子节点
public void connectChild(int childNum, Node child) {
childArray[childNum] = child;
// 子节点的父节点引用指向自己
if(child != null)
child.parent = this;
}
// 删除一个子节点
public Node disconnectChild(int childNum) {
Node tempNode = childArray[childNum]; 
childArray[childNum] = null;
return tempNode;
}
// 获取一个子节点 
public Node getChild(int childNum){
return childArray[childNum];
}
// 获取父节点
public Node getParent() {
return parent;
}
// 判断此节点是否是叶节点
public boolean isLeaf() {
return (childArray[0] == null);
}
// 获取此节点的存储数据的数量,最大为3
public int getNumItems() {
return numItems;
}
// 获取这个节点存储的某一个数据项
public DataItem getItem(int index){
return itemArray[index];
}
// 判断这个节点是否是存储了3个数据项
public boolean isFull() {
return (numItems == (ORDER -1));
}
// 判断某数据项是否存在于这个节点里面 返回数据项所在索引
public int findItem(int key) {
int i = -1;
while (itemArray[++i] != null){
if (itemArray[i].dData == key) 
return i;

return -1;
}
// 在节点里插入一个数据项,节点此时是不满的
public int insertItem(DataItem newItem) {
numItems++;
int newKey = newItem.dData;
for (int j = ORDER-2; j >= 0 ; j--) {
// 从右往左开始判断数据项是否为空
if(itemArray[j] == null)
continue;
else {
int itsKey = itemArray[j].dData;
if (newKey<itsKey) 
// 新插入的数据比这个索引位置上的旧数据小的时候,这个旧数据项右移
itemArray[j+1] = itemArray[j];
else {
// 新插入的数据比这个索引位置上的旧数据大的时候,新数据插入到旧数据项右边索引位置
itemArray[j+1] = newItem;
return (j+1);
}
}
}
// 这个节点没有存储数据项的时候把新数据项存储进去作为第一个存储值
itemArray[0] = newItem;
return 0;
}
// 删除这个节点的最大数据项
public DataItem removeItem() {
DataItem temp = itemArray[numItems-1];
itemArray[numItems-1] = null;
numItems--;
return temp;
}
// 打印这个节点的所有数据项
public void displayNode() {
for (int i = 0; i < numItems; i++) 
itemArray[i].displayItem();
System.out.println("/");
}
}







原创粉丝点击