内容结点的指针next:
P[1],P[2],…,P[M];其中P[1]指向关键字小于K[1]的子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1],K[i])的子树;
例如:
(M=3)
查找和插入
为了方便这里用了一个特殊的哨兵键,它小于其他所有键,用*表示。
一开始B树只含有一个根结点,而根结点在初始化时仅含有该哨兵键。
内部结点中的每个键都与一个结点相关联,以此结点为根的子树种,所有的键都大于等于与此结点关联的键,但小于其他所有键。
这些约定在很大程度上能够简化代码。
代码
该代码实现引入了哨兵键,代码输出则剔除了它。
代码里含有哨兵键的B树:
publicclassBTree,Value>
{
//maxchildrenperB-treenode=M-1
//(mustbeevenandgreaterthan2)
privatestaticfinalintM=4;
privateNoderoot;//rootoftheB-tree
privateintheight;//heightoftheB-tree
privateintn;//numberofkey-valuepairsintheB-tree
//helperB-treenodedatatype
privatestaticfinalclassNode
{
privateintm;//numberofchildren
privateEntry[]children=newEntry[M];//thearrayofchildren
//createanodewithkchildren
privateNode(intk)
{
m=k;
}
}
//internalnodes:
onlyusekeyandnext
//externalnodes:
onlyusekeyandvalue
privatestaticclassEntry
{
privateComparablekey;
privateObjectval;
privateNodenext;//helperfieldtoiterateoverarrayentries
publicEntry(Comparablekey,Objectval,Nodenext)
{
this.key=key;
this.val=val;
this.next=next;
}
}
/**
*InitializesanemptyB-tree.
*/
publicBTree()
{
root=newNode(0);
}
/**
*Returnstrueifthissymboltableisempty.
*@return{@codetrue}ifthissymboltableisempty;{@codefalse}otherwise
*/
publicbooleanisEmpty()
{
returnsize()==0;
}
/**
*Returnsthenumberofkey-valuepairsinthissymboltable.
*@returnthenumberofkey-valuepairsinthissymboltable
*/
publicintsize()
{
returnn;
}
/**
*ReturnstheheightofthisB-tree(fordebugging).
*
*@returntheheightofthisB-tree
*/
publicintheight()
{
returnheight;
}
/**
*Returnsthevalueassociatedwiththegivenkey.
*
*@paramkeythekey
*@returnthevalueassociatedwiththegivenkeyifthekeyisinthesymboltable
*and{@codenull}ifthekeyisnotinthesymboltable
*@throwsNullPointerExceptionif{@codekey}is{@codenull}
*/
publicValueget(Keykey)
{
if(key==null)
{
thrownewNullPointerException("keymustnotbenull");
}
returnsearch(root,key,height);
}
@SuppressWarnings("unchecked")
privateValuesearch(Nodex,Keykey,intht)
{
Entry[]children=x.children;
//externalnode到最底层叶子结点,遍历
if(ht==0)
{
for(intj=0;j{
if(eq(key,children[j].key))
{
return(Value)children[j].val;
}
}
}
//internalnode递归查找next地址
else
{
for(intj=0;j{
if(j+1==x.m||less(key,children[j+1].key))
{
returnsearch(children[j].next,key,ht-1);
}
}
}
returnnull;
}
/**
*Insertsthekey-valuepairintothesymboltable,overwritingtheoldvalue
*withthenewvalueifthekeyisalreadyinthesymboltable.
*Ifthevalueis{@codenull},thiseffectivelydeletesthekeyfromthesymboltable.
*
*@paramkeythekey
*@paramvalthevalue
*@throwsNullPointerExceptionif{@codekey}is{@codenull}
*/
publicvoidput(Keykey,Valueval)
{
if(key==null)
{
thrownewNullPointerException("keymustnotbenull");
}
Nodeu=insert(root,key,val,height);//分裂后生成的右结点
n++;
if(u==null)
{
return;
}
//needtosplitroot重组root
Nodet=newNode
(2);
t.children[0]=newEntry(root.children[0].key,null,root);
t.children[1]=newEntry(u.children[0].key,null,u);
root=t;
height++;
}
privateNodeinsert(Nodeh,Keykey,Valueval,intht)
{
intj;
Entryt=newEntry(key,val,null);
//externalnode外部结点,也是叶子结点,在树的最底层,存的是内容value
if(ht==0)
{
for(j=0;j{
if(less(key,h.children[j].key))
{
break;
}
}
}
//internalnode内部结点,存的是next地址
else
{
for(j=0;j{
if((j+1==h.m)||less(key,h.children[j+1].key))
{
Nodeu=insert(h.children[j++].next,key,val,ht-1);
if(u==null)
{
returnnull;
}
t.key=u.children[0].key;
t.next=u;
break;
}
}
}
for(inti=h.m;i>j;i--)
{
h.children[i]=h.children[i-1];
}
h.children[j]=t;
h.m++;
if(h.m{
returnnull;
}
else
{//分裂结点
returnsplit(h);
}
}
//splitnodeinhalf
privateNodesplit(Nodeh)
{
Nodet=newNode(M/2);
h.m=M/2;
for(intj=0;j{
t.children[j]=h.children[M/2+j];
}
returnt;
}
/**
*ReturnsastringrepresentationofthisB-tree(fordebugging).
*
*@returnastringrepresentationofthisB-tree.
*/
publicStringtoString()
{
returntoString(root,height,"")+"\n";
}
privateStringtoString(Nodeh,intht,Stringindent)
{
StringBuilders=newStringBuilder();
Entry[]children=h.children;
if(ht==0)
{
for(intj=0;j{
s.append(indent+children[j].key+""+children[j].val+"\n");
}
}
else
{
for(intj=0;j{
if(j>0)
{
s.append(indent+"("+children[j].key+")\n");
}
s.append(toString(children[j].next,ht-1,indent+""));
}
}
returns.toString();
}
//comparisonfunctions-makeComparableinsteadofKeytoavoidcasts
privatebooleanless(Comparablek1,Comparablek2)
{
returnpareTo(k2)<0;
}
privatebooleaneq(Comparablek1,Comparablek2)
{
returnpareTo(k2)==0;
}
/**
*Unitteststhe{@codeBTree}datatype.
*
*@paramargsthecommand-linearguments
*/
publicstaticvoidmain(String[]args)
{
BTreest=newBTree();
st.put("www.cs.princeton.edu","128.112.136.12");
st.put("www.cs.princeton.edu","128.112.136.11");
st.put(".edu","128.112.128.15");
st.put("www.yale.edu","130.132.143.21");
st.put("","209.052.165.60");
st.put("","17.112.152.32");
st.put("","207.171.182.16");
st.put("","66.135.192.87");
st.put("","64.236.16.20");
st.put("","216.239.41.99");
st.put("","199.239.136.200");
st.put("","207.126.99.140");
st.put("","143.166.224.230");
st.put("www.slashdot.org","66.35.250.151");
st.put("","199.181.135.201");
st.put("","63.111.66.11");
st.put("","216.109.118.65");
System.out.println("cs.princeton.edu:
"+st.get("www.cs.princeton.edu"));
System.out.println(":
"+st.get(""));
System.out.println(":
"+st.get(""));
System.out.println(":
"+st.get(""));
System.out.println(":
"+st.get(""));
System.out.println(":
"+st.get(""));
System.out.println();
System.out.println("size:
"+st.size());
System.out.println("height:
"+st.height());
System.out.println(st);
System.out.println();
}
}
输出:
cs.princeton.edu:
128.112.136.12
:
null
:
209.052.165.60
:
17.112.152.32
:
66.135.192.87
:
143.166.224.230
size:
17
height:
2
207.171.182.16
17.112.152.32
64.236.16.20
(www.cs.princeton.edu)
www.cs.princeton.edu128.112.136.12
www.cs.princeton.edu128.112.136.11
143.166.224.230
()
66.135.192.87
199.181.135.201
216.239.41.99
()
207.126.99.140
199.239.136.200
(www.princeton.edu)
www.princeton.edu128.112.128.15
209.052.165.60
(www.slashdot.org)
www.slashdot.org66.35.250.151
63.111.66.11
()
216.109.118.65
www.yale.edu130.132.143.21