2-3-4树指拥有最多4个子节点3个数据项的多叉树。
对非叶节点,有3种可能的情况:
- 有一个数据项的节点,总有2个子节点
- 有两个数据项的节点,总有3个子节点
- 有三个数据项的节点,总有4个子节点
2-3-4树不允许一个节点只有一个子节点,要么没有(那就是叶节点),要么有2个及以上。
二叉树的规则是关键字比节点大的子节点,是右子节点,比父节点小的,是左子节点。2-3-4树的规则相似,但是加了以下几点:
- 根是child0的子树的所有子节点的关键字小于k0
- 根是child1的子树的所有子节点的关键字大于k0小于k1
- 根是child2的子树的所有子节点的关键字大于k1小于k2
- 根是child3的子树的所有子节点的关键字大于k2
插入:找到满的节点就分裂,是叶子节点,就插入。都不是就去下一层。
2-3-4树和红黑树效率相近,缺点是有空间浪费。共同点是都通过旋转保持树的平衡。
代码:
public class DataItem {
public long dData;
public DataItem(long dData) {
this.dData = dData;
}
public void displayItem() {
System.out.print("/"+dData);
}
}
public class Node {
private static final int ORDER=4;
private int numItems;
private Node parent;
private Node childArray[]=new Node[ORDER];
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 child){
Node tempNode=childArray[child];
childArray[child]=null;
return tempNode;
}
public Node getChild(int childNum){
return childArray[childNum];
}
public Node getChild(int childNum,boolean create){
if ( create && childArray[childNum]==null){
Node node=new Node();
node.parent=this;
childArray[childNum]=node;
}
return childArray[childNum];
}
public Node getParent(){
return parent;
}
public boolean isLeaf(){
return childArray[0]==null;
}
public int getNumItems(){
return numItems;
}
public DataItem getItem(int index){
return itemArray[index];
}
public boolean isFull(){
return numItems==ORDER-1;
}
public int findItem(long key){
for (int j=0;j<ORDER;j++){
if (itemArray[j]==null){
break;
}else if (itemArray[j].dData==key){
return j;
}
}
return -1;
}
/**
* 向节点中插入一个元素
* @param newItem
* @return
*/
public int insertItem(DataItem newItem){
numItems++;
long newkey=newItem.dData;
for (int j=ORDER-2;j>=0;j--){
if (itemArray[j]==null){
continue;
}else {
long 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 dataItem=itemArray[numItems-1];
itemArray[numItems-1]=null;
numItems--;
return dataItem;
}
public void displayNode(){
for (int j=0;j<numItems;j++){
itemArray[j].displayItem();
System.out.println("/");
}
}
}
public class Tree234 {
private Node root=new Node();
/**
* 查找树中是否存在这个节点
* @param key
* @return
*/
public int find(long key){
Node curNode=root;
int childNumber;
while (true){
if ((childNumber=curNode.findItem(key))!=-1){
return childNumber;
}else if (curNode.isLeaf()){
return -1;
}else {
curNode=getNextChild(curNode,key);
}
}
}
public void insert(long dValue){
Node curNode=root;
DataItem tempItem=new DataItem(dValue);
while (true){
if (curNode.isFull()){
spilt(curNode);
curNode=curNode.getParent();
curNode=getNextChild(curNode,dValue);
}else if (curNode.isLeaf()){
break;
}else {
curNode=getNextChild(curNode,dValue);//更换为孩子节点,那么curNode的parent节点一定是没有满的
}
}
curNode.insertItem(tempItem);
}
private void spilt(Node curNode) {
DataItem itemB,itemC;
Node parent,child2,child3;
int itemIndex;
itemC=curNode.removeItem();
itemB=curNode.removeItem();
child2=curNode.disconnectChild(2);
child3=curNode.disconnectChild(3);
Node newRight=new Node();
if (curNode==root){
root=new Node();
parent=root;
root.connectChild(0,curNode);
}else {
parent=curNode.getParent();
}
itemIndex=parent.insertItem(itemB);
int n=parent.getNumItems();
for (int j=n-1;j>itemIndex;j--){
Node temp=parent.disconnectChild(j);
parent.connectChild(itemIndex+1,temp);
}
parent.connectChild(itemIndex+1,newRight);
newRight.insertItem(itemC);
newRight.connectChild(0,child2);
newRight.connectChild(1,child3);
}
private Node getNextChild(Node curNode, long key) {
int j;
int numItems=curNode.getNumItems();
for (j=0;j<numItems;j++){
if (key<curNode.getItem(j).dData){
return curNode.getChild(j);
}
}
return curNode.getChild(j);
}
}