具备n(n≥)个节点的有穷集合D与D上的关系集合R构成的结构T。即T:=(D,R)。html
树的逻辑表示法:树形表示、文氏图表示、凹入表示、嵌套括号表示。java
有序树、无序树。node
孩子节点、双亲节点、子孙节点、祖先节点、兄弟节点算法
节点的度、树的度、节点的层次、树的深度或称高度。(层次、深度从1起)数组
叶子节点、分支节点、内部节点。(度为0的节点、度非0的节点,非根分支节点)app
对于度为k的树:dom
一、节点数=度数+1ide
二、第i层节点数:k(i-1),i≥1post
三、高为i的k叉树节点数最多:(ki-1)/(k-1),i≥1性能
四、n个节点的k叉树深度最小为:ceil( logk( n(k-1)+1 ) )
多重链表:定长链节点个数(二叉树等)、不定长链节点个数
三重链表:每一个节点三个指针域(第一个孩子节点、双亲节点、第一个兄弟节点)
二叉树是有序树,有5中基本形态。(度不超过2的树不必定是二叉树,由于二叉树还要求左右子树有序不能颠倒)
n个节点能够构建卡特兰数 f(n)= (k=1~n)Σ(f(k-1)f(n-k)) = (C2n n)/(n+1) ,f(0)=f(1)=1种形态的二叉树。对于有n个节点的有序序列,其BST树也是卡特兰数种。
一、节点数=度数+1
二、第i层节点数:2(i-1),i≥1
三、高为i的二叉树节点数最多:2i-1,i≥1
四、n个节点的二叉树深度最小为:ceil( log2(n+1) ),为理想平衡二叉树时取最小值
五、度为0的节点数=度为2的节点数+1。(由于 节点数n=n0+n1+n2 且 分支数 n-1=n1+2n2,联立可得之)
六、n个节点的彻底二叉树从1起对节点从上到下从左到右的编号,编号为i的节点:父节点编号为 floor(i/2),除非该节点已为父节点;左孩子节点编号为2i,除非2i>n即该节点已为叶子节点;右孩子编号为2i+1,除非2i+1>n即右孩子不存在。
推而广之,对于彻底m叉树编号为i的节点,其父节点编号为 floor((i+m-2)/m ) ,第j个孩子编号为 mi+j-m+1 。
一、顺序存储:数组。(适用于彻底二叉树的存储,通常二叉树能够经过填充虚拟节点当成彻底二叉树来存储。缺点是浪费空间)
二、链式存储:
二叉链表(左孩子、右孩子):n个节点的二叉树有n+1个空指针域(空指针域即2n0+n1=n2+1+n0+n1=n+1)。线索二叉树经过利用空指针域指向直接前驱、后继节点来避免遍历时使用堆栈,如中序线索二叉树。
三叉链表(父节点、左孩子、右孩子)
根据输入的序列构创建用二叉链表存储的二叉树。这里假定序列为字符串,每一个字符对应树中一个节点。
输入:
首先说下补空,由输入序列(前缀、中缀、后缀皆可)构建二叉树时,若是序列里没有标记一些节点结束信息,则因为没法识别结束或哪些是叶节点从而不能由序列构建出树。所谓补空就是在序列中加入一些特殊字符如'#',加在哪?方式1:一般是序列对应的树的节点的空指针域中,也即度为1和0的节点的空孩子,此时对于n个节点的序列其补空数为n+1;方式2:也能够只对度为1的节点补空。有趣的是若是输入序列是表达式,则用前种补空方式时只有叶节点即操做数补空、用后种补空时没有节点被补空。一般用前种方式补空,某些特殊状况下才用后者。
加括号:把根节点和其左右子树当作一体,在其外围加上括号。
百言不如一图,树T按方式一、2分别被补空为T一、T2:
对输入序列:由单一序列就想构建二叉树则须要序列包含补空信息或序列自己包含额外信息(如前缀表达式序列操做符为内部节点操做数为叶节点),要下不补空就能构建二叉树则需多个序列。
总结:(带括号补空:前、中、后序递归; 不带括号补空:前序递归、后序非递归、层次非递归; 不带括号不补空:先后缀表达式、前中序、中后序等),其中,由 不带括号内补空层次序列 构建二叉树最直观最适用,如LeetCode中与树有关的题目的输入。
一、一般而言,输入序列里须要包含补空信息,此时可采用 前序、中序、后序 遍历输入序列来创建二叉树,只要构建过程遍历采用的序与输入序列采用的序同样。分为两种状况:
1)带括号的补空序列(方式1或2)(可按方式1或2补空,无论是T一、T2,有几个内部节点就有几个括号,即为T的节点数或内部节点数)
a、带括号、补空,前序序列(递归构建):
1 void createPreOrder_withBrackets(char prefix[],BTREE &T) 2 { 3 //要求输入的前缀序列带括号 ,并含有对度为0和1的节点的补空特殊字符。此时非特殊字符都成了“内部节点”,有几个非特殊字符就有几个括号。 4 //固然也能够只对度为1的补空,此时有几个非叶节点的非特殊字符就有几个括号。若输入的是前缀表达式,则此状况的内部节点其实就是操做符,叶节点是操做数。 5 //例子:度为0和1的补空:( A( B( D##) ( E( G#( H##) ) #) ) ( C( F##) #) ),只对度为1的补空:( A( BD( E( G#H )# ) )( CF# ) ) 6 //特殊例子(前缀表达式):度为0和1的补空:( *( +( A##) ( /( -( B##) ( C##) ) ( D##) ) ) ( E##) ) ,只对度为1的补空:(*(+A(/(-BC)D))E) 7 char x=nextToken(prefix); 8 9 if(x=='#') 10 { 11 T=NULL; 12 } 13 else 14 { 15 T=(BTREE)malloc(sizeof(BTNode)); 16 T->lchild=NULL; 17 T->rchild=NULL; 18 19 if(x=='(') 20 {//处理括号里的表达式 21 x=nextToken(prefix);//表达式的操做符 22 T->data=x; 23 24 createPreOrder_withBrackets(prefix,T->lchild);//表达式的左操做数 25 26 createPreOrder_withBrackets(prefix,T->rchild);//表达式的右操做数 27 28 nextToken(prefix);//右括号 29 } 30 else 31 { 32 T->data=x; 33 } 34 } 35 }
若输入按方式1补空,则括号数为T1的内部节点数即T的节点数,如 ( *( +( A##) ( /( -( B##) ( C##) ) ( D##) ) ) ( E##) ) 、 ( A( B( D##) ( E( G#( H##) ) #) ) ( C( F##) #) ) ;
若输入按方式2补空,则括号数为T2的内部节点数即T的内部节点数。如 (*(+A(/(-BC)D))E) 、 ( A( BD( E( G#H )# ) )( CF# ) ) ,能够发现前者就是前缀表达式,只不过多了括号。
能够发现,不论哪一种补空方式,括号数都是补空后的树的内部节点数。想一想,表达式树的内部节点都是操做符叶节点都是操做数,其中缀表达式的括号数就是操做符(内部节点)数,与这里的括号数有何联系?
b、带括号、补空,中序序列(递归构建):与上相似,改变一行代码顺序便可。
c、带括号、补空,中序序列(递归构建):一样,改变一行代码顺序便可。
输入示例:
|--------------------------------------------------------------------------------------------------------------------------------------------|
| 方式1:度为一、0的节点补空 | 方式2:度为1的节点补空 |
| 前缀:( *( +( A##) ( /( -( B##) ( C##) ) ( D##) ) ) ( E##) ) | (*(+A(/(-BC)D))E) |
| 示例1 中缀:( ( ( #A#) +( ( ( #B#) -( #C#) ) /( #D#) ) ) *( #E#) ) | ((A+((B-C)/D))*E) |
| 后缀:(((##A)(((##B)(##C)-)(##D)/)+)(##E)*) | ((A((BC-)D/)+)E*) |
|---------------------------------------------------------------------------------------------------------------------------------------------|
| 前缀:( A( B( D##) ( E( G#( H##) ) #) ) ( C( F##) #) ) | ( A( BD( E( G#H )# ) )( CF# ) ) |
| 示例2 中缀:( ( ( #D#) B( ( #G( #H#) ) E#) ) A( ( #F#) C#) ) | ( ( DB( ( #GH )E# ) )A( FC# ) ) |
| 后缀:(((##D)((#(##H)G)#E)B)((##F)#C)A) | ( ( D( ( #HG )#E )B )( F#C )A ) |
|_____________________________________________________________________________________|
能够发现,此种方法能对带括号的中缀表达式构建表达式树。
2)不带括号的补空序列(只能方式1)。实际上本方式使用得最多,加括号是为了程序解析但不利于人阅读,括号数一多不信你不会被搞蒙。。。
a、不带括号、全补空、前序序列(递归构建):
1 void createPreOrder(char prefixStr[],BTREE &T) 2 { 3 char x=nextToken(prefixStr); 4 if(x=='#') 5 { 6 T=NULL; 7 } 8 else 9 { 10 T=(BTREE)malloc(sizeof(BTNode)); 11 T->data=x; 12 createPreOrder(prefixStr,T->lchild); 13 createPreOrder(prefixStr,T->rchild); 14 } 15 }
输入示例(上表第一列前序者去掉括号便可): +A##/-B##C##D##E## 、 AB D## E G# H### C F## #
b、不带括号,全补空、中序序列,能够发现参数无论什么中序序列补空后每一个字符左右均为#,因此其对应的树不惟一,故不带括号的中序补空序列无法构建树。
c、不带括号、全补空、后序序列(非递归构建):每遇到一个非补空字符时为之建立一个新节点并从栈中取两个节点做为其孩子
1 void createPostOrder(char infix[],BTREE &T) 2 {// 3 int stackSize=100; 4 BTREE stack[stackSize],p; 5 int top=-1; 6 char x; 7 while(1) 8 { 9 x=nextToken(infix); 10 if(x=='\0') 11 { 12 break; 13 } 14 else if(x=='#') 15 { 16 stack[++top]=NULL; 17 } 18 else 19 { 20 p=(BTREE)malloc(sizeof(BTNode)); 21 p->data=x; 22 p->lchild=stack[top-1];; 23 p->rchild=stack[top]; 24 stack[top-1]=p; 25 top--; 26 } 27 } 28 T=stack[0]; 29 }
输入示例(上表第一列后序者去掉括号便可)
d、不带括号、按彻底二叉树形式补空、层次遍历序列(非递归构建)
1 void createLayerOrder(char layerSeq[],int n,BTREE &T) 2 {//输入序列是广度优先序列,且按彻底二叉树形式补空,由于要利用父子节点间编号的关系。如 "12#34#####5" 3 if(n<0) return; 4 5 BTREE node[n]; 6 int i,j; 7 for(i=0;i<n;i++) 8 { 9 if(layerSeq[i]!='#') 10 { 11 node[i]=(BTREE)malloc(sizeof(BTNode)); 12 node[i]->data=layerSeq[i]; 13 node[i]->lchild=NULL; 14 node[i]->rchild=NULL; 15 if(i==0) 16 { 17 T=node[i]; 18 } 19 else 20 { 21 j=(i-1)/2;//父节点下标 22 if(2*j+1==i)node[j]->lchild=node[i];//当前节点是父节点的左孩子 23 else node[j]->rchild=node[i] ;//当前节点是父节点的右孩子 24 } 25 } 26 } 27 }
e、不带括号、内补空、层次序列,最直接最经常使用
将内补空序列转为彻底二叉树形式补空序列,而后按d处理或直接在转换的过程当中创建:
1 //输入层次遍历序列(内补空),构建二叉树 2 void createLayerOrder2(char layerSeq[],int n,BTREE &T) 3 { 4 //先将序列转为彻底二叉树形式补空的序列 5 const int M=100; 6 7 if(n<=0) return; 8 9 char input[M];//node[]用于以彻底二叉树形式存储节点 10 BTREE node[M]; 11 12 int i=0,nonBlank=0; 13 while(i<n) 14 {//统计非空字符数,做为下面循环结束的条件 15 input[i]=layerSeq[i]; 16 if(input[i]!='#') 17 { 18 nonBlank++; 19 } 20 i++; 21 } 22 23 i=0; 24 int j; 25 while(nonBlank>0) 26 { 27 if(input[i]!='#') 28 { 29 nonBlank--; 30 {//法1,转换为彻底二叉树补空形式过程当中构建 31 node[i]=(BTREE)malloc(sizeof(BTNode)); 32 node[i]->data=input[i]; 33 node[i]->lchild=NULL; 34 node[i]->rchild=NULL; 35 if(i==0) 36 { 37 T=node[i]; 38 } 39 else 40 { 41 j=(i-1)/2; 42 if(2*j+1==i)node[j]->lchild=node[i]; 43 else if(2*j+2==i) node[j]->rchild=node[i]; 44 } 45 } 46 } 47 else 48 { 49 //后移两位 50 for(j=n-1;j>=2*i+1;j--) 51 { 52 input[j+2]=input[j]; 53 } 54 n+=2; 55 input[2*i+1]='#'; 56 input[2*i+2]='#'; 57 } 58 i++; 59 } 60 61 62 {//法2,调用,根据彻底二叉树形式补空序列构建二叉树 63 // input[n]='\0'; 64 // printf("%s\n",input); 65 // createLayerOrder(input,n,T) ;//输入二叉树形式补空的序列,构建二叉树 66 } 67 }
二、要想输入时不需补空:
1)要么同时提供中序、前序序列 或 同时提供中序、后序序列 或 同时提供中序、层次序列。
法一(三种都可用此法):根据中序序列下标采用逐点插入法构建“二叉搜索树”——前序、层次序列从头至尾各元素依次插入;后序序列从后到前各元素依次插入。
1 //根据 中序序列 和 后序|前序|层次序列 构建二叉树。采用逐点插入法构建“二叉搜索树”。 2 int cbiGetIndex(char inorder[],int n,char val) 3 {//获取给定值在中序序列的下标 4 int i=0; 5 while(i<n && inorder[i]!=val) 6 { 7 i++; 8 } 9 return i; 10 } 11 void cbiBuildBST(BTREE &T,char inorder[],int n,char val) 12 {//插入一个值到二叉搜索树 13 if(T==NULL) 14 { 15 T=(BTREE)malloc(sizeof(BTNode)); 16 T->data=val; 17 T->lchild=NULL; 18 T->rchild=NULL; 19 } 20 else if(cbiGetIndex(inorder,n,val) < cbiGetIndex(inorder,n,T->data)) 21 { 22 cbiBuildBST(T->lchild,inorder,n,val); 23 } 24 else 25 { 26 cbiBuildBST(T->rchild,inorder,n,val); 27 } 28 } 29 void createByInAndOtherOrder(BTREE &T,char input[],int isInputPostOrder,char inorder[],int n) 30 {//根据 中序序列 和 后序|前序|层次序列 构建二叉树。采用逐点插入法构建“二叉搜索树”。 31 printf("%s %d\n",input,n); 32 int i; 33 if(isInputPostOrder) 34 {//若input是后序序列,从后往前依次插入各元素 35 for(i=n-1;i>=0;i--) 36 { 37 cbiBuildBST(T,inorder,n,input[i]); 38 } 39 } 40 else{//不然input是前序或后序序列,从前日后依次插入各元素 41 for(i=0;i<n;i++) 42 { 43 cbiBuildBST(T,inorder,n,input[i]); 44 } 45 } 46 }
法二(前两种可用此法):取前序序列首元素,找到在中序序列的位置,此位置分割成的左右两部分就是左子树和右子树,两部分的长度分别对应前序序列接下来两部分的长度,递归进行。
a、由前序、中序序列构建二叉树:(不带括号、不补空、递归构建)。
1 //由前序、中序序列(不补空不带括号)构建二叉树。有重复元素的话树不惟一,因此不能有重 2 void createByPreInOrder(BTREE &T,char preorder[],int preStart,int preEnd,char inorder[],int inStart,int inEnd) 3 {//求前序序列首元素在中序序列的位置,此位置左边为左子树序列、右边为右子树序列,二者的长度分别对应前序序列接下来的两段长度,接下来递归进行。 4 if(preStart>preEnd || inStart>inEnd || preEnd-preStart!=inEnd-inStart) 5 { 6 return; 7 } 8 9 //求前序序列首元素在中序序列的位置 及 中序序列被该元素分红的左右子序列的长度 10 int pivot; 11 for(pivot=inStart; pivot<=inEnd && preorder[preStart]!=inorder[pivot];pivot++); 12 int leftLen=pivot-inStart;//位置左边的元素个数 13 int rightLen=inEnd-pivot;//位置右边的元素个数 14 15 T=(BTREE)malloc(sizeof(BTNode)); 16 T->data=preorder[preStart]; 17 T->lchild=NULL; 18 T->rchild=NULL; 19 if(leftLen>0) 20 { 21 createByPreInOrder(T->lchild,preorder, preStart+1, preStart+1+leftLen-1, inorder, inStart, pivot-1); 22 } 23 if(rightLen>0) 24 { 25 createByPreInOrder(T->rchild,preorder, preStart+1+leftLen, preEnd, inorder, pivot+1, inEnd); 26 } 27 }
b、由后序、中序序列构建二叉树:(不带括号、不补空、递归构建)。与上述相似,只不过每次取的是后序序列的末尾值来构建新节点
1 //由后序、中序序列(不补空不带括号)构建二叉树。有重复元素的话树不惟一,因此不能有重 2 void createByPostInOrder(BTREE &T,char postorder[],int postStart,int postEnd,char inorder[],int inStart,int inEnd) 3 {//求后序序列末元素在中序序列的位置,此位置左边为左子树序列、右边为右子树序列,二者的长度分别对应后序序列从首元素开始的两段长度,接下来递归进行。 4 if(postStart>postEnd || inStart>inEnd || postEnd-postStart!=inEnd-inStart) 5 { 6 return; 7 } 8 9 //求前序序列首元素在中序序列的位置 及 中序序列被该元素分红的左右子序列的长度 10 int pivot; 11 for(pivot=inStart; pivot<=inEnd && postorder[postEnd]!=inorder[pivot];pivot++); 12 int leftLen=pivot-inStart; 13 int rightLen=inEnd-pivot; 14 15 T=(BTREE)malloc(sizeof(BTNode)); 16 T->data=postorder[postEnd]; 17 T->lchild=NULL; 18 T->rchild=NULL; 19 if(leftLen>0) 20 { 21 createByPostInOrder(T->lchild,postorder, postStart, postStart+leftLen-1, inorder, inStart, pivot-1); 22 } 23 if(rightLen>0) 24 { 25 createByPostInOrder(T->rchild,postorder, postStart+leftLen, postEnd-1, inorder, pivot+1, inEnd); 26 } 27 }
注意:
若提供了二叉查找树的后序遍历序列则便可构建出该树,由于二叉查找树的中序序列是递增的,咱们能够从后序序列获得中序序列;实际上,不获取也可,从后往前依次将每一个元素插入便可。(给定BST的前序序列时与此相似)。此时其实是上述法一的特殊状况。
2)要么序列自己包含额外信息:如前缀表达式或后缀表达式因操做符为内部节点操做数为叶节点,可直接根据序列之构建表达式树;带括号的中缀表达式(每一个运算符都有对应的括号)括号能提供额外信息,所以也能直接根据之创建树。
由表达式序列构建表达式树示例:由表达式序列构建表达式树-MarchOn (前缀、中缀递归,后缀非递归)
a、前缀表达式序列构建表达式树(不带括号、不补空、递归构建):
1 void createPrefix_recursive(char prefix[],BTREE &T) 2 {//递归方式_由前缀表达式构建表达式树,输入示例:*+A/-BCDE 3 char x=nextToken(prefix); 4 5 T=(BTREE)malloc(sizeof(BTNode)); 6 T->data=x; 7 T->lchild=NULL; 8 T->rchild=NULL; 9 10 if(!isOpNum(x))//是操做符。前缀表达式的最后一个字符必定是操做数,因此下面的递归会中止。 11 { 12 createPrefix_recursive(prefix,T->lchild); 13 createPrefix_recursive(prefix,T->rchild); 14 } 15 }
输入示例: *+A/-BCDE
b、中缀表达式序列构建表达式树(带括号、不补空,递归构建):直接用带括号补空的方法(一、一、b)中的方法。不过因为表达式树内部节点为操做符叶子节点为操做数不存在为度为1的节点,因此构建方法能够稍微简化:
1 void createInfix_recursive(char infix[],BTREE &T) 2 {//递归方式_由中缀表达式构建表达式树,要求输入的中缀表达式加括号,有几个操做数就几个括号 3 char x=nextToken(infix); 4 5 T=(BTREE)malloc(sizeof(BTNode)); 6 T->lchild=NULL; 7 T->rchild=NULL; 8 9 if(x=='(') 10 {//处理括号里的表达式 11 createInfix_recursive(infix,T->lchild);//表达式的左操做数 12 13 x=nextToken(infix);//表达式的操做符 14 T->data=x; 15 16 createInfix_recursive(infix,T->rchild);//表达式的右操做数 17 nextToken(infix);//右括号 18 } 19 else 20 { 21 T->data=x; 22 } 23 }
输入示例: ((A+((B-C)/D))*E)
c、后缀表达式序列构建表达式树(不带括号、不补空,非递归构建):
1 #define M 100 2 void createPostfix_nonrecursive(char postfix[],BTREE &T) 3 {//非递归方式_由后缀表达式构建表达式树 4 BTREE stack[M],p; 5 int top=-1; 6 char x; 7 while(1) 8 { 9 x=nextToken(postfix); 10 if(x=='\0') 11 { 12 break; 13 } 14 15 p=(BTREE)malloc(sizeof(BTNode)) ; 16 p->data=x; 17 p->lchild=NULL; 18 p->rchild=NULL; 19 20 if(isOpNum(x)) 21 {//操做数 22 stack[++top]=p; 23 } 24 else 25 {//操做符 26 p->lchild=stack[top-1]; 27 p->rchild=stack[top]; 28 stack[top-1]=p; 29 top--; 30 } 31 } 32 T=stack[0]; 33 }
输入示例: ABC-D/+E*
这里总结了根据不一样输入形式构建二叉树的方法,当遇到不是这些形式的时,能够向这些形式靠。如A( (B ( D,E(G)), C(F(,H) ) ) )
可是,也不要那么死板局限于这里的方法,条条大路通罗马,确定还会有其余方法的。
附:上述关于树建立的完整代码:
1 #include<stdio.h> 2 #include<malloc.h> 3 typedef struct node 4 { 5 int data; 6 struct node* lchild; 7 struct node* rchild; 8 }BTNode,*BTREE; 9 10 11 //遍历 12 13 void searchPrefix(BTREE T) 14 { 15 if(T!=NULL) 16 { 17 printf("%c",T->data); 18 19 searchPrefix(T->lchild); 20 21 searchPrefix(T->rchild); 22 } 23 } 24 void searchInfix(BTREE T) 25 { 26 if(T!=NULL) 27 {//访问到内部节点时左右加括号 ,所以几个内部节点就有几个括号,若是树是表达式树 ,则获得了带括号的中缀表达式 28 // if(T->lchild!=NULL || T->rchild!=NULL){ printf("( "); } 29 searchInfix(T->lchild); 30 // if((T->lchild!=NULL || T->rchild!=NULL) && (T->lchild==NULL)){ printf("#"); }//内部节点的空孩子用特殊符号代替 31 32 printf("%c",T->data); 33 34 searchInfix(T->rchild); 35 // if((T->lchild!=NULL || T->rchild!=NULL) && (T->rchild==NULL)){ printf("#"); }//内部节点的空孩子用特殊符号代替 36 // if(T->lchild!=NULL || T->rchild!=NULL){ printf(" )"); } 37 } 38 } 39 void searchPostfix(BTREE T) 40 { 41 if(T!=NULL) 42 {//访问到内部节点时左右加括号 ,所以几个内部节点就有几个括号,若是树是表达式树 ,则获得了带括号的后缀表达式 43 // if(T->lchild!=NULL || T->rchild!=NULL){ printf("( "); } 44 searchPostfix(T->lchild); 45 // if((T->lchild!=NULL || T->rchild!=NULL) && (T->lchild==NULL)){ printf("#"); }//内部节点的空孩子用特殊符号代替 46 47 searchPostfix(T->rchild); 48 // if((T->lchild!=NULL || T->rchild!=NULL) && (T->rchild==NULL)){ printf("#"); }//内部节点的空孩子用特殊符号代替 49 50 printf("%c",T->data); 51 // if(T->lchild!=NULL || T->rchild!=NULL){ printf(" )"); } 52 } 53 } 54 55 56 //构建 57 char nextToken(char str[]) //读取下一字符,略过空格 58 { 59 static int pos=0; 60 while(str[pos]!='\0' && str[pos]==' '){ pos++; } 61 return str[pos++]; 62 } 63 64 65 void createPreOrder_withBrackets_c(char prefix[],BTREE *T) 66 {//为了能更改T,这里采用了指针,为了更清晰简洁,能够用C++里的引用 67 char x=nextToken(prefix); 68 69 if(x=='#') 70 { 71 *T=NULL; 72 } 73 else 74 { 75 *T=(BTREE)malloc(sizeof(BTNode)); 76 (*T)->lchild=NULL; 77 (*T)->rchild=NULL; 78 79 if(x=='(') 80 {//处理括号里的表达式 81 x=nextToken(prefix);//表达式的操做符 82 (*T)->data=x; 83 84 createPreOrder_withBrackets_c(prefix,&((*T)->lchild));//表达式的左操做数 85 86 createPreOrder_withBrackets_c(prefix,&((*T)->rchild));//表达式的右操做数 87 88 nextToken(prefix);//右括号 89 } 90 else 91 { 92 (*T)->data=x; 93 } 94 } 95 } 96 97 void createPreOrder_withBrackets(char prefix[],BTREE &T) 98 { 99 //要求输入的前缀序列带括号 ,并含有对度为0和1的节点的补空特殊字符。此时非特殊字符都成了“内部节点”,有几个非特殊字符就有几个括号。 100 //固然也能够只对度为1的补空,此时有几个非叶节点的非特殊字符就有几个括号。若输入的是前缀表达式,则此状况的内部节点其实就是操做符,叶节点是操做数。 101 //例子:度为0和1的补空:( A( B( D##) ( E( G#( H##) ) #) ) ( C( F##) #) ),只对度为1的补空:( A( BD( E( G#H )# ) )( CF# ) ) 102 //特殊例子(前缀表达式):度为0和1的补空:( *( +( A##) ( /( -( B##) ( C##) ) ( D##) ) ) ( E##) ) ,只对度为1的补空:(*(+A(/(-BC)D))E) 103 char x=nextToken(prefix); 104 105 if(x=='#') 106 { 107 T=NULL; 108 } 109 else 110 { 111 T=(BTREE)malloc(sizeof(BTNode)); 112 T->lchild=NULL; 113 T->rchild=NULL; 114 115 if(x=='(') 116 {//处理括号里的表达式 117 x=nextToken(prefix);//表达式的操做符 118 T->data=x; 119 120 createPreOrder_withBrackets(prefix,T->lchild);//表达式的左操做数 121 122 createPreOrder_withBrackets(prefix,T->rchild);//表达式的右操做数 123 124 nextToken(prefix);//右括号 125 } 126 else 127 { 128 T->data=x; 129 } 130 } 131 } 132 133 void createInOrder_withBrackets(char infix[],BTREE &T) 134 {//要求输入的序列带括号 ,内部节点才带括号;度为1的节点缺失的孩子补特殊字符(度为0的可补可不补) 135 char x=nextToken(infix); 136 137 if(x=='#') 138 { 139 T=NULL; 140 } 141 else 142 { 143 T=(BTREE)malloc(sizeof(BTNode)); 144 T->lchild=NULL; 145 T->rchild=NULL; 146 147 if(x=='(') 148 {//处理括号里的表达式 149 createInOrder_withBrackets(infix,T->lchild);//表达式的左操做数 150 151 x=nextToken(infix);//表达式的操做符 152 T->data=x; 153 154 createInOrder_withBrackets(infix,T->rchild);//表达式的右操做数 155 156 nextToken(infix);//右括号 157 } 158 else 159 { 160 T->data=x; 161 } 162 } 163 } 164 165 void createPostOrder_withBrackets(char infix[],BTREE &T) 166 {//要求输入的序列带括号 ,内部节点才带括号;度为1的节点缺失的孩子补特殊字符(度为0的可补可不补) 167 char x=nextToken(infix); 168 169 if(x=='#') 170 { 171 T=NULL; 172 } 173 else 174 { 175 T=(BTREE)malloc(sizeof(BTNode)); 176 T->lchild=NULL; 177 T->rchild=NULL; 178 179 if(x=='(') 180 {//处理括号里的表达式 181 createPostOrder_withBrackets(infix,T->lchild);//表达式的左操做数 182 183 createPostOrder_withBrackets(infix,T->rchild);//表达式的右操做数 184 185 x=nextToken(infix);//表达式的操做符 186 T->data=x; 187 188 nextToken(infix);//右括号 189 } 190 else 191 { 192 T->data=x; 193 } 194 } 195 } 196 197 void createPreOrder(char prefixStr[],BTREE &T) 198 {//输入序列为 全补空、不带括号 的序列 199 char x=nextToken(prefixStr); 200 if(x=='#') 201 { 202 T=NULL; 203 } 204 else 205 { 206 T=(BTREE)malloc(sizeof(BTNode)); 207 T->data=x; 208 createPreOrder(prefixStr,T->lchild); 209 createPreOrder(prefixStr,T->rchild); 210 } 211 } 212 213 214 void createPostOrder(char infix[],BTREE &T) 215 {// 输入序列为 全补空、不带括号 的序列 216 int stackSize=100; 217 BTREE stack[stackSize],p; 218 int top=-1; 219 char x; 220 while(1) 221 { 222 x=nextToken(infix); 223 if(x=='\0') 224 { 225 break; 226 } 227 else if(x=='#') 228 { 229 stack[++top]=NULL; 230 } 231 else 232 { 233 p=(BTREE)malloc(sizeof(BTNode)); 234 p->data=x; 235 p->lchild=stack[top-1];; 236 p->rchild=stack[top]; 237 stack[top-1]=p; 238 top--; 239 } 240 } 241 T=stack[0]; 242 } 243 244 //输入层次遍历序列(全补空),构建二叉树 245 void createLayerOrder(char layerSeq[],int n,BTREE &T) 246 {//输入序列是广度优先序列,且按彻底二叉树形式补空,由于要利用父子节点间编号的关系。如 "12#34#####5" 247 //构建后的实际节点数≤n 248 if(n<=0) return; 249 250 BTREE node[n]; 251 int i,j; 252 for(i=0;i<n;i++) 253 { 254 if(layerSeq[i]!='#') 255 { 256 node[i]=(BTREE)malloc(sizeof(BTNode)); 257 node[i]->data=layerSeq[i]; 258 node[i]->lchild=NULL; 259 node[i]->rchild=NULL; 260 if(i==0) 261 { 262 T=node[i]; 263 } 264 else 265 { 266 j=(i-1)/2;//父节点下标 267 if(2*j+1==i)node[j]->lchild=node[i];//当前节点是父节点的左孩子 268 else node[j]->rchild=node[i] ;//当前节点是父节点的右孩子 269 } 270 } 271 } 272 } 273 274 //输入层次遍历序列(内补空),构建二叉树 275 void createLayerOrder2(char layerSeq[],int n,BTREE &T) 276 { 277 //先将序列转为彻底二叉树形式补空的序列 278 const int M=100; 279 280 if(n<=0) return; 281 282 char input[M];//node[]用于以彻底二叉树形式存储节点 283 BTREE node[M]; 284 285 int i=0,nonBlank=0; 286 while(i<n) 287 {//统计非空字符数,做为下面循环结束的条件 288 input[i]=layerSeq[i]; 289 if(input[i]!='#') 290 { 291 nonBlank++; 292 } 293 i++; 294 } 295 296 i=0; 297 int j; 298 while(nonBlank>0) 299 { 300 if(input[i]!='#') 301 { 302 nonBlank--; 303 {//法1,转换为彻底二叉树补空形式过程当中构建 304 node[i]=(BTREE)malloc(sizeof(BTNode)); 305 node[i]->data=input[i]; 306 node[i]->lchild=NULL; 307 node[i]->rchild=NULL; 308 if(i==0) 309 { 310 T=node[i]; 311 } 312 else 313 { 314 j=(i-1)/2; 315 if(2*j+1==i)node[j]->lchild=node[i]; 316 else if(2*j+2==i) node[j]->rchild=node[i]; 317 } 318 } 319 } 320 else 321 { 322 //后移两位 323 for(j=n-1;j>=2*i+1;j--) 324 { 325 input[j+2]=input[j]; 326 } 327 n+=2; 328 input[2*i+1]='#'; 329 input[2*i+2]='#'; 330 } 331 i++; 332 } 333 334 335 {//法2,调用,根据彻底二叉树形式补空序列构建二叉树 336 // input[n]='\0'; 337 // printf("%s\n",input); 338 // createLayerOrder(input,n,T) ;//输入二叉树形式补空的序列,构建二叉树 339 } 340 } 341 342 //由前序、中序序列(不补空不带括号)构建二叉树。有重复元素的话树不惟一,因此不能有重 343 void createByPreInOrder(BTREE &T,char preorder[],int preStart,int preEnd,char inorder[],int inStart,int inEnd) 344 {//求前序序列首元素在中序序列的位置,此位置左边为左子树序列、右边为右子树序列,二者的长度分别对应前序序列接下来的两段长度,接下来递归进行。 345 if(preStart>preEnd || inStart>inEnd || preEnd-preStart!=inEnd-inStart) 346 { 347 return; 348 } 349 350 //求前序序列首元素在中序序列的位置 及 中序序列被该元素分红的左右子序列的长度 351 int pivot; 352 for(pivot=inStart; pivot<=inEnd && preorder[preStart]!=inorder[pivot];pivot++); 353 int leftLen=pivot-inStart;//位置左边的元素个数 354 int rightLen=inEnd-pivot;//位置右边的元素个数 355 356 T=(BTREE)malloc(sizeof(BTNode)); 357 T->data=preorder[preStart]; 358 T->lchild=NULL; 359 T->rchild=NULL; 360 if(leftLen>0) 361 { 362 createByPreInOrder(T->lchild,preorder, preStart+1, preStart+1+leftLen-1, inorder, inStart, pivot-1); 363 } 364 if(rightLen>0) 365 { 366 createByPreInOrder(T->rchild,preorder, preStart+1+leftLen, preEnd, inorder, pivot+1, inEnd); 367 } 368 } 369 370 //由后序、中序序列(不补空不带括号)构建二叉树。有重复元素的话树不惟一,因此不能有重 371 void createByPostInOrder(BTREE &T,char postorder[],int postStart,int postEnd,char inorder[],int inStart,int inEnd) 372 {//求后序序列末元素在中序序列的位置,此位置左边为左子树序列、右边为右子树序列,二者的长度分别对应后序序列从首元素开始的两段长度,接下来递归进行。 373 if(postStart>postEnd || inStart>inEnd || postEnd-postStart!=inEnd-inStart) 374 { 375 return; 376 } 377 378 //求前序序列首元素在中序序列的位置 及 中序序列被该元素分红的左右子序列的长度 379 int pivot; 380 for(pivot=inStart; pivot<=inEnd && postorder[postEnd]!=inorder[pivot];pivot++); 381 int leftLen=pivot-inStart; 382 int rightLen=inEnd-pivot; 383 384 T=(BTREE)malloc(sizeof(BTNode)); 385 T->data=postorder[postEnd]; 386 T->lchild=NULL; 387 T->rchild=NULL; 388 if(leftLen>0) 389 { 390 createByPostInOrder(T->lchild,postorder, postStart, postStart+leftLen-1, inorder, inStart, pivot-1); 391 } 392 if(rightLen>0) 393 { 394 createByPostInOrder(T->rchild,postorder, postStart+leftLen, postEnd-1, inorder, pivot+1, inEnd); 395 } 396 } 397 398 //根据 中序序列 和 后序|前序|层次序列 构建二叉树。采用逐点插入法构建“二叉搜索树”。 399 int cbiGetIndex(char inorder[],int n,char val) 400 {//获取给定值在中序序列的下标 401 int i=0; 402 while(i<n && inorder[i]!=val) 403 { 404 i++; 405 } 406 return i; 407 } 408 void cbiBuildBST(BTREE &T,char inorder[],int n,char val) 409 {//插入一个值到二叉搜索树 410 if(T==NULL) 411 { 412 T=(BTREE)malloc(sizeof(BTNode)); 413 T->data=val; 414 T->lchild=NULL; 415 T->rchild=NULL; 416 } 417 else if(cbiGetIndex(inorder,n,val) < cbiGetIndex(inorder,n,T->data)) 418 { 419 cbiBuildBST(T->lchild,inorder,n,val); 420 } 421 else 422 { 423 cbiBuildBST(T->rchild,inorder,n,val); 424 } 425 } 426 void createByInAndOtherOrder(BTREE &T,char input[],int isInputPostOrder,char inorder[],int n) 427 {//根据 中序序列 和 后序|前序|层次序列 构建二叉树。采用逐点插入法构建“二叉搜索树”。 428 printf("%s %d\n",input,n); 429 int i; 430 if(isInputPostOrder) 431 {//若input是后序序列,从后往前依次插入各元素 432 for(i=n-1;i>=0;i--) 433 { 434 cbiBuildBST(T,inorder,n,input[i]); 435 } 436 } 437 else{//不然input是前序或后序序列,从前日后依次插入各元素 438 for(i=0;i<n;i++) 439 { 440 cbiBuildBST(T,inorder,n,input[i]); 441 } 442 } 443 } 444 445 //二叉查找树建立、查找、删除(递归、非递归) 446 void insertBinarySearchTree_nonrecursive(BTREE &T,char item) 447 { 448 BTREE p,q; 449 p=(BTREE)malloc(sizeof(BTNode)); 450 p->data=item; 451 p->lchild=NULL; 452 p->rchild=NULL; 453 if(T==NULL) T=p; 454 else 455 { 456 q=T; 457 while(1) 458 { 459 if(item < q->data) 460 { 461 if(q->lchild!=NULL) q=q->lchild; 462 else 463 { 464 q->lchild=p; 465 break; 466 } 467 } 468 else 469 { 470 if(q->rchild!=NULL) q=q->rchild; 471 else 472 { 473 q->rchild=p; 474 break; 475 } 476 } 477 } 478 } 479 } 480 void insertBinarySearchTree_recursive(BTREE &T,char item) 481 { 482 if(T==NULL) 483 { 484 T=(BTREE)malloc(sizeof(BTNode)); 485 T->data=item; 486 T->lchild=NULL; 487 T->rchild=NULL; 488 } 489 else if(item< T->data) 490 { 491 insertBinarySearchTree_recursive(T->lchild,item); 492 } 493 else 494 { 495 insertBinarySearchTree_recursive(T->rchild,item); 496 } 497 } 498 499 BTREE searchBinarySearchTree_nonrecursive(BTREE T,char item) 500 { 501 if(T==NULL) 502 return NULL; 503 BTREE p=T; 504 while(p!=NULL) 505 { 506 if(p->data==item) 507 return p; 508 else if(p->data<item) 509 p=p->lchild; 510 else 511 p=p->rchild; 512 } 513 } 514 515 BTREE searchBinarySearchTree_recursive(BTREE T,char item) 516 { 517 if(T==NULL || T->data==item) 518 return T; 519 else if(T->data < item) 520 searchBinarySearchTree_recursive(T->lchild,item); 521 else 522 searchBinarySearchTree_recursive(T->rchild,item); 523 } 524 525 void deleteBSTNode(BTREE &T,char key) 526 {//删除二叉查找树中的一个节点。也能够借助后序非递归遍从来实现 ,此时栈顶元素存在的话为当前节点的父节点 527 if(T==NULL)return; 528 else if(key<T->data)deleteBSTNode(T->lchild,key); 529 else if(key>T->data)deleteBSTNode(T->rchild,key); 530 else 531 { 532 if(T->lchild==NULL) 533 { 534 BTREE tmp=T; 535 T=T->rchild; 536 free(tmp); 537 } 538 else if(T->rchild==NULL) 539 { 540 BTREE tmp=T; 541 T=T->lchild; 542 free(tmp) ; 543 } 544 else 545 { 546 //找右子树的最小节点(最左边)的值替换被删节点的值 547 BTREE p=T->rchild; 548 while(p->lchild!=NULL) 549 { 550 p=p->lchild; 551 } 552 T->data=p->data; 553 deleteBSTNode(T->rchild,p->data); 554 555 //也能够找左子树最右的值 556 // BTREE p=T->lchild; 557 // while(p->lchild!=NULL) 558 // { 559 // p=p->lchild; 560 // } 561 // T->data=p->data; 562 // deleteBSTNode(T->lchild,p->data); 563 } 564 } 565 } 566 567 void createBinarySearchTree(BTREE &T,char input[],int n) 568 { 569 int i; 570 for(i=0;i<n;i++) 571 { 572 insertBinarySearchTree_nonrecursive(T,input[i]); 573 // insertBinarySearchTree_recursive(T,input[i]); 574 } 575 576 for(i=0;i<n;i++) 577 {//验证递归查找和非递归查找的正确性 578 if(searchBinarySearchTree_nonrecursive(T,input[i])!=searchBinarySearchTree_recursive(T,input[i])) 579 { 580 printf("error in searchBinarySearchTree\n"); 581 } 582 } 583 } 584 585 586 587 int main() 588 { 589 590 //测试1,特殊序列(表达式 )。度为1的节点空孩子必定要补空,度为0的能够不补;因为表达式内部节点为操做符度都为故不须要补空 591 592 //度为1的节点补空 593 //(*(+A(/(-BC)D))E) 594 //((A+((B-C)/D))*E) 595 //((A((BC-)D/)+)E*) 596 597 //度为一、0的节点补空 598 //( *( +( A##) ( /( -( B##) ( C##) ) ( D##) ) ) ( E##) ) 599 //( ( ( #A#) +( ( ( #B#) -( #C#) ) /( #D#) ) ) *( #E#) ) 600 //(((##A)(((##B)(##C)-)(##D)/)+)(##E)*) 601 602 //测试2,普通序列 603 604 //度为1的节点补空 605 //( A( BD( E( G#H )# ) )( CF# ) ) 606 //( ( DB( ( #GH )E# ) )A( FC# ) ) 607 //( ( D( ( #HG )#E )B )( F#C )A ) 608 609 //度为一、0的节点补空 610 //( A( B( D##) ( E( G#( H##) ) #) ) ( C( F##) #) ) 611 //( ( ( #D#) B( ( #G( #H#) ) E#) ) A( ( #F#) C#) ) 612 //(((##D)((#(##H)G)#E)B)((##F)#C)A) 613 614 615 616 //测试1,特殊序列(表达式 ) ,度为一、0的节点都得补空 617 //*+A##/-B##C##D##E## 618 //#A#+#B#-#C#/#D#*#E# 619 //##A##B##C-##D/+##E* 620 621 //测试2,普通序列 ,度为一、0的节点都得补空 622 //ABD##EG#H###CF### 623 //#D#B#G#H#E#A#F#C# 624 //##D###HG#EB##F#CA 625 626 BTREE T=NULL; 627 628 //加括号:全补空或内补空,前缀、中缀、后缀 629 // char str[]="(*(+A(/(-BC)D))E)"; 630 //char str[]="( *(+(A##)(/(-(B##)(C##))(D##)))(E##) )"; 631 // char str[]="( A( BD( E( G#H )# ) )( CF# ) )"; 632 //char str[]="( A( B( D##) ( E( G#( H##) ) #) ) ( C( F##) #) )"; 633 // createPreOrder_withBrackets(str,T); 634 635 // char str[]="((A+((B-C)/D))*E)"; 636 // char str[]="( ( DB( ( #GH )E# ) )A( FC# ) )"; 637 //char str[]="( ( ( #A#) +( ( ( #B#) -( #C#) ) /( #D#) ) ) *( #E#) )"; 638 // createInOrder_withBrackets(str,T); 639 640 // char str[]="( ( A((BC-)D/)+ )E* )"; 641 //char str[]="(((##A)(((##B)(##C)-)(##D)/)+)(##E)*)"; 642 // char str[]="( ( D( ( #HG )#E )B )( F#C )A )"; 643 // createPostOrder_withBrackets(str,T); 644 645 646 //不加括号:全补空 ,前缀、后缀、广度优先 647 // char str[]="*+A##/-B##C##D##E##"; 648 // char str[]="AB D## E G# H### C F## #"; 649 // createPreOrder(str,T); 650 651 // char str[]="#A#+#B#-#C#/#D#*#E#";//不带括号的中序序列的树是不惟一的,因此无法构建 652 // char str[]="#D#B#G#H#E#A#F#C#"; 653 // createInOrder(str,T); 654 655 // char str[]="##A##B##C-##D/+##E*"; 656 // char str[]="##D # ##H G#EB##F#CA"; 657 // createPostOrder(str,T); 658 659 // char layerSeq[]="12#34#####5"; 660 // createLayerOrder(layerSeq,sizeof(layerSeq)/sizeof(char)-1,T);//广度优先、二叉树形式补空 661 char layerSeq2[]="12#34###5"; 662 createLayerOrder2(layerSeq2,sizeof(layerSeq2)/sizeof(char)-1,T);//广度优先、内补空 。能够将序列转换为彻底二叉树形式补空再用上述方法构建,也能够在转换过程当中构建。 663 664 //由前序、中序序列 或 后序、中序序列 或 中序、层次序列 构建二叉树。不补空、不加括号。 665 char inorder[]="254163"; 666 char preorder[]="124536"; 667 char postorder[]="542631"; 668 char layerorder[]="123465"; 669 // createByInAndOtherOrder(T,postorder,1,inorder,sizeof(inorder)-1);//法1,三种输入方式均可用此法构建二叉树 670 // createByInAndOtherOrder(T,preorder,0,inorder,sizeof(inorder)-1); 671 // createByInAndOtherOrder(T,layerorder,0,inorder,sizeof(inorder)-1); 672 // createByPreInOrder(T,preorder,0,sizeof(preorder)-1-1,inorder,0,sizeof(inorder)-1-1) ;//法2,知道前序、中序 673 // createByPostInOrder(T,postorder,0,sizeof(postorder)-1-1,inorder,0,sizeof(inorder)-1-1);//法2,知道后序、中序 674 675 //二叉查找树建立、查找(递归、非递归)、删除 676 // char data[]="43265178"; 677 // createBinarySearchTree(T,data,sizeof(data)/sizeof(char)-1); 678 // deleteBSTNode(T,'4'); 679 680 681 682 searchPrefix(T); 683 printf("\n"); 684 searchInfix(T); 685 printf("\n"); 686 searchPostfix(T); 687 printf("\n"); 688 689 return 0; 690 }
采用链式存储:深度优先(前序、中序、后序)、广度优先(层次)遍历。(递归、非递归)
采用顺序存储:深度优先(前序、中序、后序)、广度优先(层次)遍历。(递归、非递归),输入为以彻底二叉树补空的层次遍历序列,所以遍历方法与采用链式存储的相同,只是改成借助节点编号来反映节点间的父子关系。
复杂度:
深度优先:时间复杂度O(n)、空间复杂度O(h)
广度优先:时间复杂度O(n)、空间复杂度O(n)
一、链式存储的遍历:(输入的是树的头结点指针)
1)、递归遍历:
前序、中序、后序遍历(大同小异):
1 void searchPrefix(BTREE T) 2 { 3 if(T!=NULL) 4 { 5 printf("%c",T->data); 6 7 searchPrefix(T->lchild); 8 9 searchPrefix(T->rchild); 10 } 11 }
能够加以改进,以打印括号信息或补空信息。
1 void searchPrefix(BTREE T) 2 {//方式1补空:全部的空指针域用特殊字符替代 3 if(T!=NULL) 4 { 5 printf("%c",T->data); 6 7 searchPrefix(T->lchild); 8 9 searchPrefix(T->rchild); 10 } else 11 { 12 printf("#"); 13 } 14 } 15 16 void searchPrefix(BTREE T) 17 {//方式2补空:内部节点的空指针域用特殊字符替代 18 if(T!=NULL) 19 { 20 printf("%c",T->data); 21 22 searchPrefix(T->lchild); 23 if((T->lchild!=NULL || T->rchild!=NULL) && (T->lchild==NULL)){ printf("#"); }//内部节点的空孩子用特殊符号代替 24 25 searchPrefix(T->rchild); 26 if((T->lchild!=NULL || T->rchild!=NULL) && (T->rchild==NULL)){ printf("#"); }//内部节点的空孩子用特殊符号代替 27 } 28 } 29 30 void searchPrefix(BTREE T) 31 {//打印括号 32 if(T!=NULL) 33 { 34 if(T->lchild!=NULL || T->rchild!=NULL){ printf("( "); } 35 printf("%c",T->data); 36 37 searchPrefix(T->lchild); 38 39 searchPrefix(T->rchild); 40 if(T->lchild!=NULL || T->rchild!=NULL){ printf(" )"); } 41 } 42 }
层次遍历:
1 #define M 100 2 void searchLayer(BTREE T) 3 {//广度优先递归遍历,与非递归遍历几乎同样,非递归遍历甚至更方便 4 static BTREE queue[M],p; 5 static int front=-1,rear=-1,isInitial=1; 6 if(T!=NULL) 7 { 8 if(isInitial) 9 { 10 queue[++rear]=T; 11 isInitial=0; 12 } 13 if(front<rear) 14 { 15 p=queue[++front]; 16 printf("%c",p->data); 17 if(p->lchild!=NULL)queue[++rear]=p->lchild; 18 if(p->rchild!=NULL)queue[++rear]=p->rchild; 19 searchLayer(T); 20 } 21 } 22 } 23 24 //也可借助深度遍从来完成,如下是Java版,功能是输出同层的节点 25 /** 26 * Definition for a binary tree node. 27 * public class TreeNode { 28 * int val; 29 * TreeNode left; 30 * TreeNode right; 31 * TreeNode(int x) { val = x; } 32 * } 33 */ 34 public class Solution { 35 public List<List<Integer>> levelOrder(TreeNode root) { 36 List<List<Integer>> res=new ArrayList<>(); 37 if(root==null) 38 { 39 return res; 40 } 41 helper(0,root,res); 42 return res; 43 } 44 public void helper(int depth,TreeNode node,List<List<Integer>>res) 45 {//经过 前序深度优先遍历 来实现 递归版的广度优先遍历 46 if(node==null) return; 47 if(res.size()==depth) 48 { 49 res.add(new ArrayList<Integer>()); 50 } 51 res.get(depth).add(node.val); 52 helper(depth+1,node.left,res); 53 helper(depth+1,node.right,res); 54 } 55 }
2)、非递归遍历:
前序、中序遍历:
1 #define M 100 2 void preOrder(BTREE T) 3 { 4 BTREE stack[M],p=T; 5 int top=-1; 6 if(T!=NULL) 7 { 8 do 9 { 10 while(p!=NULL) 11 { 12 //visit(p); 13 printf("%c",p->data); 14 15 stack[++top]=p; 16 p=p->lchild; 17 } 18 p=stack[top--]; 19 p=p->rchild; 20 }while(!(p==NULL && top==-1)); 21 } 22 } 23 void inOrder(BTREE T) 24 { 25 BTREE stack[M],p=T; 26 int top=-1; 27 if(T!=NULL) 28 { 29 do 30 { 31 while(p!=NULL) 32 { 33 stack[++top]=p; 34 p=p->lchild; 35 } 36 p=stack[top--]; 37 38 //visit(p); 39 printf("%c",p->data); 40 41 42 p=p->rchild; 43 }while(!(p==NULL && top==-1)); 44 } 45 }
后序遍历:(此遍历在访问节点时,栈中保存了根节点到当前节点的父节点的全部节点)
1 void postOrder(BTREE T) 2 {//后序非递归遍历,在访问节点时,栈里保存了根到当前节点的全部节点 3 BTREE stack1[M],p=T; 4 int top=-1,flag,stack2[M];//flag用于标记节点是否能访问 5 if(T!=NULL) 6 { 7 do 8 { 9 while(p!=NULL)//① 10 { 11 stack1[++top]=p; 12 stack2[top]=0; 13 p=p->lchild; 14 } 15 p=stack1[top]; 16 flag=stack2[top--]; 17 if(flag==0) 18 {//不能访问 19 stack1[++top]=p; 20 stack2[top]=1; 21 p=p->rchild; 22 } 23 else 24 {//能访问 25 //visit(p); 26 printf("%c",p->data); 27 28 p=NULL;//为了跳过① 29 } 30 }while(!(p==NULL && top==-1)); 31 } 32 }
层次遍历:
1 void layerOrder(BTREE T) 2 { 3 BTREE queue[M],p; 4 int front=-1,rear=-1; 5 if(T!=NULL) 6 { 7 queue[++rear]=T; 8 9 while(front<rear) 10 { 11 p=queue[++front]; 12 13 //visit(p); 14 printf("%c",p->data); 15 16 if(p->lchild!=NULL) 17 { 18 queue[++rear]=p->lchild; 19 } 20 if(p->rchild!=NULL) 21 { 22 queue[++rear]=p->rchild; 23 } 24 } 25 } 26 }
二、顺序存储遍历:(输入的是彻底二叉树形式的 层次遍历 序列,即除末层外,各层上的空节点都要用特殊字符填充;遍历方式与链式存储的非递归遍历几乎同样,只是这里用数组下标表示父子节点关系,而链式存储中用到是指针)
1)递归遍历:
前序、中序、后序、层次遍历:
1 //bt为输入序列,补空为彻底二叉树形式 2 void searchPrefixOfArray(char bt[],int n,int i) 3 { 4 if(i<n && bt[i]!='#') 5 { 6 printf("%c",bt[i]); 7 searchPrefixOfArray(bt,n,2*i+1); 8 searchPrefixOfArray(bt,n,2*i+2); 9 } 10 } 11 void searchInfixOfArray(char bt[],int n,int i) 12 { 13 if(i<n && bt[i]!='#') 14 { 15 searchInfixOfArray(bt,n,2*i+1); 16 printf("%c",bt[i]); 17 searchInfixOfArray(bt,n,2*i+2); 18 } 19 } 20 void searchPostfixOfArray(char bt[],int n,int i) 21 { 22 if(i<n && bt[i]!='#') 23 { 24 searchPostfixOfArray(bt,n,2*i+1); 25 searchPostfixOfArray(bt,n,2*i+2); 26 printf("%c",bt[i]); 27 } 28 } 29 void searchLayerOfArray(char bt[],int n,int i) 30 { 31 while(i<n) 32 { 33 if(bt[i]!='#') 34 { 35 printf("%c",bt[i]); 36 } 37 i++; 38 } 39 }
2)非递归遍历:
前序、中序遍历:
1 void preOrderOfArray(char bt[],int n) 2 {//输入序列按彻底二叉树形式补空 3 int stack[M],top=-1,i=0; 4 if(n>0) 5 { 6 do 7 { 8 while(i<n && bt[i]!='#') 9 { 10 //visio(bt[i]); 11 printf("%c",bt[i]); 12 13 stack[++top]=i; 14 i=2*i+1; 15 } 16 i=stack[top--]; 17 i=2*i+2; 18 }while(!((i>=n || bt[i]=='#') && top==-1)); 19 } 20 } 21 22 void inOrderOfArray(char bt[],int n) 23 {//输入序列按彻底二叉树形式补空 24 int stack[M],top=-1,i=0; 25 if(n>0) 26 { 27 do 28 { 29 while(i<n && bt[i]!='#') 30 { 31 stack[++top]=i; 32 i=2*i+1; 33 } 34 i=stack[top--]; 35 36 //visio(bt[i]); 37 printf("%c",bt[i]); 38 39 i=2*i+2; 40 }while(!((i>=n || bt[i]=='#') && top==-1)); 41 } 42 }
后序遍历:
1 void postOrderOfArray(char bt[],int n) 2 {//输入序列按彻底二叉树形式补空 3 int stack1[M],stack2[M],top=-1,i=0,flag; 4 if(n>0) 5 { 6 do 7 { 8 while(i<n && bt[i]!='#') 9 { 10 stack1[++top]=i; 11 stack2[top]=0; 12 i=2*i+1; 13 } 14 i=stack1[top]; 15 flag=stack2[top--]; 16 17 if(flag==0) 18 { 19 stack1[++top]=i; 20 stack2[top]=1; 21 i=2*i+2; 22 } 23 else 24 { 25 //visit(bt[i]); 26 printf("%c",bt[i]); 27 28 i=n; 29 } 30 }while(!((i>=n || bt[i]=='#') && top==-1)); 31 } 32 }
层次遍历:
1 void layerOrderOfArray(char bt[],int n) 2 {//输入序列按彻底二叉树形式补空 3 int queue[M],front=-1,rear=-1,i; 4 if(n>0) 5 { 6 queue[++rear]=0; 7 while(front<rear) 8 { 9 i=queue[++front]; 10 11 //visit(bt[i]); 12 printf("%c",bt[i]); 13 14 if(2*i+1<n && bt[2*i+1]!='#') queue[++rear]=2*i+1; 15 if(2*i+2<n && bt[2*i+2]!='#') queue[++rear]=2*i+2; 16 } 17 } 18 }
附:上述遍历的完整代码:
1 #include<stdio.h> 2 #include<malloc.h> 3 typedef struct node 4 { 5 int data; 6 struct node* lchild; 7 struct node* rchild; 8 }BTNode,*BTREE; 9 10 //链式存储递归遍历(深度优先、广度优先) 11 void searchPrefix(BTREE T) 12 { 13 if(T!=NULL) 14 { 15 printf("%c",T->data); 16 17 searchPrefix(T->lchild); 18 19 searchPrefix(T->rchild); 20 } 21 } 22 void searchInfix(BTREE T) 23 { 24 if(T!=NULL) 25 { 26 searchInfix(T->lchild); 27 28 printf("%c",T->data); 29 30 searchInfix(T->rchild); 31 } 32 } 33 void searchPostfix(BTREE T) 34 { 35 if(T!=NULL) 36 { 37 searchPostfix(T->lchild); 38 39 searchPostfix(T->rchild); 40 41 printf("%c",T->data); 42 } 43 } 44 45 #define M 100 46 void searchLayer(BTREE T) 47 {//广度优先递归遍历,也可借助深度遍从来完成 48 static BTREE queue[M],p; 49 static int front=-1,rear=-1,isInitial=1; 50 if(T!=NULL) 51 { 52 if(isInitial) 53 { 54 queue[++rear]=T; 55 isInitial=0; 56 } 57 if(front<rear) 58 { 59 p=queue[++front]; 60 printf("%c",p->data); 61 if(p->lchild!=NULL)queue[++rear]=p->lchild; 62 if(p->rchild!=NULL)queue[++rear]=p->rchild; 63 searchLayer(T); 64 } 65 } 66 } 67 68 //链式存储非递归遍历(深度优先、广度优先) 69 void preOrder(BTREE T) 70 { 71 BTREE stack[M],p=T; 72 int top=-1; 73 if(T!=NULL) 74 { 75 do 76 { 77 while(p!=NULL) 78 { 79 //visit(p); 80 printf("%c",p->data); 81 82 stack[++top]=p; 83 p=p->lchild; 84 } 85 p=stack[top--]; 86 p=p->rchild; 87 }while(!(p==NULL && top==-1)); 88 } 89 } 90 void inOrder(BTREE T) 91 { 92 BTREE stack[M],p=T; 93 int top=-1; 94 if(T!=NULL) 95 { 96 do 97 { 98 while(p!=NULL) 99 { 100 stack[++top]=p; 101 p=p->lchild; 102 } 103 p=stack[top--]; 104 105 //visit(p); 106 printf("%c",p->data); 107 108 109 p=p->rchild; 110 }while(!(p==NULL && top==-1)); 111 } 112 } 113 void postOrder(BTREE T) 114 {//后序非递归遍历,在访问节点时,栈里保存了根到当前节点父节点的全部节点 115 BTREE stack1[M],p=T; 116 int top=-1,flag,stack2[M];//flag用于标记节点是否能访问 117 if(T!=NULL) 118 { 119 do 120 { 121 while(p!=NULL)//① 122 { 123 stack1[++top]=p; 124 stack2[top]=0; 125 p=p->lchild; 126 } 127 p=stack1[top]; 128 flag=stack2[top--]; 129 if(flag==0) 130 {//不能访问 131 stack1[++top]=p; 132 stack2[top]=1; 133 p=p->rchild; 134 } 135 else 136 {//能访问 137 //visit(p); 138 printf("%c",p->data); 139 140 p=NULL;//为了跳过① 141 } 142 }while(!(p==NULL && top==-1)); 143 } 144 } 145 146 void layerOrder(BTREE T) 147 { 148 BTREE queue[M],p; 149 int front=-1,rear=-1; 150 if(T!=NULL) 151 { 152 queue[++rear]=T; 153 154 while(front<rear) 155 { 156 p=queue[++front]; 157 158 //visit(p); 159 printf("%c",p->data); 160 161 if(p->lchild!=NULL) 162 { 163 queue[++rear]=p->lchild; 164 } 165 if(p->rchild!=NULL) 166 { 167 queue[++rear]=p->rchild; 168 } 169 } 170 } 171 } 172 173 //顺序存储递归遍历(深度优先、广度优先) 174 void searchPrefixOfArray(char bt[],int n,int i) 175 { 176 if(i<n && bt[i]!='#') 177 { 178 printf("%c",bt[i]); 179 searchPrefixOfArray(bt,n,2*i+1); 180 searchPrefixOfArray(bt,n,2*i+2); 181 } 182 } 183 void searchInfixOfArray(char bt[],int n,int i) 184 { 185 if(i<n && bt[i]!='#') 186 { 187 searchInfixOfArray(bt,n,2*i+1); 188 printf("%c",bt[i]); 189 searchInfixOfArray(bt,n,2*i+2); 190 } 191 } 192 void searchPostfixOfArray(char bt[],int n,int i) 193 { 194 if(i<n && bt[i]!='#') 195 { 196 searchPostfixOfArray(bt,n,2*i+1); 197 searchPostfixOfArray(bt,n,2*i+2); 198 printf("%c",bt[i]); 199 } 200 } 201 void searchLayerOfArray(char bt[],int n,int i) 202 { 203 while(i<n) 204 { 205 if(bt[i]!='#') 206 { 207 printf("%c",bt[i]); 208 } 209 i++; 210 } 211 } 212 213 //顺序存储非递归遍历(深度优先、广度优先) 214 void preOrderOfArray(char bt[],int n) 215 {//输入序列按彻底二叉树形式补空 216 int stack[M],top=-1,i=0; 217 if(n>0) 218 { 219 do 220 { 221 while(i<n && bt[i]!='#') 222 { 223 //visio(bt[i]); 224 printf("%c",bt[i]); 225 226 stack[++top]=i; 227 i=2*i+1; 228 } 229 i=stack[top--]; 230 i=2*i+2; 231 }while(!((i>=n || bt[i]=='#') && top==-1)); 232 } 233 } 234 235 void inOrderOfArray(char bt[],int n) 236 {//输入序列按彻底二叉树形式补空 237 int stack[M],top=-1,i=0; 238 if(n>0) 239 { 240 do 241 { 242 while(i<n && bt[i]!='#') 243 { 244 stack[++top]=i; 245 i=2*i+1; 246 } 247 i=stack[top--]; 248 249 //visio(bt[i]); 250 printf("%c",bt[i]); 251 252 i=2*i+2; 253 }while(!((i>=n || bt[i]=='#') && top==-1)); 254 } 255 } 256 257 void postOrderOfArray(char bt[],int n) 258 {//输入序列按彻底二叉树形式补空 259 int stack1[M],stack2[M],top=-1,i=0,flag; 260 if(n>0) 261 { 262 do 263 { 264 while(i<n && bt[i]!='#') 265 { 266 stack1[++top]=i; 267 stack2[top]=0; 268 i=2*i+1; 269 } 270 i=stack1[top]; 271 flag=stack2[top--]; 272 273 if(flag==0) 274 { 275 stack1[++top]=i; 276 stack2[top]=1; 277 i=2*i+2; 278 } 279 else 280 { 281 //visit(bt[i]); 282 printf("%c",bt[i]); 283 284 i=n; 285 } 286 }while(!((i>=n || bt[i]=='#') && top==-1)); 287 } 288 } 289 290 void layerOrderOfArray(char bt[],int n) 291 {//输入序列按彻底二叉树形式补空 292 int queue[M],front=-1,rear=-1,i; 293 if(n>0) 294 { 295 queue[++rear]=0; 296 while(front<rear) 297 { 298 i=queue[++front]; 299 300 //visit(bt[i]); 301 printf("%c",bt[i]); 302 303 if(2*i+1<n && bt[2*i+1]!='#') queue[++rear]=2*i+1; 304 if(2*i+2<n && bt[2*i+2]!='#') queue[++rear]=2*i+2; 305 } 306 } 307 } 308 309 310 //构建 311 char nextToken(char str[]) //读取下一字符,略过空格 312 { 313 static int pos=0; 314 while(str[pos]!='\0' && str[pos]==' '){ pos++; } 315 return str[pos++]; 316 } 317 318 319 void createPreOrder(char prefixStr[],BTREE *T) 320 {//输入序列为 全补空、不带括号 的序列 321 char x=nextToken(prefixStr); 322 if(x=='#') 323 { 324 *T=NULL; 325 } 326 else 327 { 328 *T=(BTREE)malloc(sizeof(BTNode)); 329 (*T)->data=x; 330 createPreOrder(prefixStr,&((*T)->lchild)); 331 createPreOrder(prefixStr,&((*T)->rchild)); 332 } 333 } 334 335 int main() 336 { 337 338 //一、链式存储遍历 339 BTREE T=NULL; 340 //char str[]="*+A##/-B##C##D##E##"; 341 char str[]="AB D## E G# H### C F## #"; 342 createPreOrder(str,&T); 343 344 //1.一、链式存储递归遍历 345 printf("链式存储递归遍历:\n"); 346 searchPrefix(T); 347 printf("\n"); 348 349 searchInfix(T); 350 printf("\n"); 351 352 searchPostfix(T); 353 printf("\n"); 354 355 searchLayer(T); 356 printf("\n"); 357 358 //1.二、链式存储非递归遍历 359 printf("\n链式存储非递归遍历:\n"); 360 preOrder(T); 361 printf("\n"); 362 363 inOrder(T); 364 printf("\n"); 365 366 postOrder(T); 367 printf("\n"); 368 369 layerOrder(T); 370 printf("\n"); 371 372 //二、顺序存储遍历 373 char input[]="abcd#f#####e"; 374 int n=sizeof(input)-1; 375 376 //2.一、顺序存储递归遍历 377 printf("\n顺序存储递归遍历:%d\n",n); 378 searchPrefixOfArray(input,n,0); 379 printf("\n"); 380 381 searchInfixOfArray(input,n,0); 382 printf("\n"); 383 384 searchPostfixOfArray(input,n,0); 385 printf("\n"); 386 387 searchLayerOfArray(input,n,0); 388 printf("\n"); 389 390 //2.二、顺序存储非递归遍历 391 printf("\n顺序存储非递归遍历:%d\n",n); 392 preOrderOfArray(input,n); 393 printf("\n"); 394 395 inOrderOfArray(input,n); 396 printf("\n"); 397 398 postOrderOfArray(input,n); 399 printf("\n"); 400 401 layerOrderOfArray(input,n); 402 printf("\n"); 403 404 return 0; 405 }
经过遍从来销毁:后序递归遍历;后序非递归遍历(此时栈中保存了当前节点的双亲节点到根节点的全部节点)
一、理想平衡二叉树(只有最后一层可能不满)
满二叉树(是理想平衡二叉树,且各层都满)
彻底二叉树(是理想平衡二叉树,且最后一层节点依次从左填到右)
二、正则(正规)二叉树:只有度为0或2的节点的二叉树
三、线索二叉树:将二叉树的空指针域用来存储直接前驱、直接后继节点(称为线索)的二叉树,这样遍历就不须要用栈了。
经过遍历二叉树进行二叉树的线索化,根据遍历方法的不一样分为前序线索二叉树、中序线索二叉树、后序线索二叉树
前序线索二叉树中不能找到某些节点的直接前驱节点、后序线索二叉树不能找到某些二叉树的直接后继节点,所以一般用中序线索二叉树。
四、哈夫曼树(最优二叉树):带权路径长度WPL最小的二叉树。
WPL=Σ(叶节点权值×路径长度)= 非根节点的权值和 = 非叶节点的权值和
没有度为1的节点(即哈夫曼树是正则二叉树)、给定权值序列构造的哈夫曼树不惟一但WPL相同。
五、二叉查找树(亦称二叉排序树、二叉搜索树)BST:每一个节点的左子树的全部节点的值小于该节点值,右子树的全部节点值小于该节点值的二叉树。
查找长度:
内部节点、外部节点、平均查找长度ASL(成功时ASL一、失败时ASL二、综合)、内路径长度IPL、外路径长度EPL。EPL=IPL+2n,
某个节点查找成功时比较次数=所在层数=路径+1,故全部节点查找成功的比较次数=IPL+n;某个值查找失败的比较次数=最后一次比较的叶节点的层=外部节点的外路径长度,故全部节点查找失败的比较次数为EPL
ASL1=(IPL+n)/n,ASL2=EPL/(n+1)
ASL=(IPL+n+EPL)/(n+n+1)=(3n+IPL)/(2n+1),当IPL最小时平均查找长度最小。
种数:对包含n个数的有序序列,其BST树有卡特兰数种。
二叉查找树的中序遍历获得升序序列,判断二叉树是不是二叉查找树能够看中序遍历序列是否升序来断定(递归、非递归都可),固然,还有其余更好的方法。
1)二叉查找树建立(递归、非递归):(只给定BST的前序序列便可构建出BST,依次从前日后插入每一个元素便可;只给定后序序列时相似,只不过是从后彻底插入)
1 void insertBinarySearchTree_nonrecursive(BTREE &T,char item) 2 { 3 BTREE p,q; 4 p=(BTREE)malloc(sizeof(BTNode)); 5 p->data=item; 6 p->lchild=NULL; 7 p->rchild=NULL; 8 if(T==NULL) T=p; 9 else 10 { 11 q=T; 12 while(1) 13 { 14 if(item < q->data) 15 { 16 if(q->lchild!=NULL) q=q->lchild; 17 else 18 { 19 q->lchild=p; 20 break; 21 } 22 } 23 else 24 { 25 if(q->rchild!=NULL) q=q->rchild; 26 else 27 { 28 q->rchild=p; 29 break; 30 } 31 } 32 } 33 } 34 } 35 void insertBinarySearchTree_recursive(BTREE &T,char item) 36 { 37 if(T==NULL) 38 { 39 T=(BTREE)malloc(sizeof(BTNode)); 40 T->data=item; 41 T->lchild=NULL; 42 T->rchild=NULL; 43 } 44 else if(item< T->data) 45 { 46 insertBinarySearchTree_recursive(T->lchild,item); 47 } 48 else 49 { 50 insertBinarySearchTree_recursive(T->rchild,item); 51 } 52 } 53 void createBinarySearchTree(BTREE &T,char input[],int n) 54 { 55 int i; 56 for(i=0;i<n;i++) 57 { 58 // insertBinarySearchTree_nonrecursive(T,input[i]); 59 insertBinarySearchTree_recursive(T,input[i]); 60 } 61 }
2)二叉查找树查找节点(递归、非递归):
1 BTREE searchBinarySearchTree_nonrecursive(BTREE T,char item) 2 { 3 BTREE p=T; 4 while(p!=NULL) 5 { 6 if(p->data==item) 7 return p; 8 else if(p->data<item) 9 p=p->lchild; 10 else 11 p=p->rchild; 12 } 13 return p; 14 } 15 16 BTREE searchBinarySearchTree_recursive(BTREE T,char item) 17 { 18 if(T==NULL || T->data==item) 19 return T; 20 else if(T->data < item) 21 searchBinarySearchTree_recursive(T->lchild,item); 22 else 23 searchBinarySearchTree_recursive(T->rchild,item); 24 }
3)二叉查找树删除节点(删除后维护BST的性质,BST形状可能不惟一):相关:LeetCode450
先找到节点,若找到,则进行删除操做:
a、如果叶子节点则直接删除;
b、不然,若左孩子空、右孩子非空,则删掉后用右孩子代替之;
c、不然,若左孩子非空、右孩子空,则删掉后用左孩子替代之;
d、不然,值用右子树的最小节点(即右子树的最左节点)的值代替之,并维护右子树即:对该最左节点进行a或b操做。固然,也能够用左子树的最大节点(即左子树的最右节点)的值代替之并对该最右节点进行a或c操做。
递归法:
1 void deleteBSTNode(BTREE &T,char key) 2 {//删除二叉查找树中的一个节点。也能够借助后序非递归遍从来实现 ,此时栈顶元素存在的话为当前节点的父节点 3 if(T==NULL)return; 4 else if(key<T->data)deleteBSTNode(T->lchild,key); 5 else if(key>T->data)deleteBSTNode(T->rchild,key); 6 else 7 { 8 if(T->lchild==NULL) 9 { 10 BTREE tmp=T; 11 T=T->rchild; 12 free(tmp); 13 } 14 else if(T->rchild==NULL) 15 { 16 BTREE tmp=T; 17 T=T->lchild; 18 free(tmp) ; 19 } 20 else 21 { 22 //找右子树的最小节点(最左边)的值替换被删节点的值 23 BTREE p=T->rchild; 24 while(p->lchild!=NULL) 25 { 26 p=p->lchild; 27 } 28 T->data=p->data; 29 deleteBSTNode(T->rchild,p->data); 30 31 //也能够找左子树最右的值 32 // BTREE p=T->lchild; 33 // while(p->rchild!=NULL) 34 // { 35 // p=p->rchild; 36 // } 37 // T->data=p->data; 38 // deleteBSTNode(T->lchild,p->data); 39 } 40 } 41 }
非递归法:(用后序非递归遍历,比较麻烦)
4)验证是不是二叉查找树:二叉查找树的中序遍历获得升序序列,判断二叉树是不是二叉查找树能够看中序遍历序列是否升序来断定(递归、非递归都可),固然,还有其余更好的方法,查看相关--LeetCode98。
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 public class Solution {//经过中序遍历。是BST 等价于 中序遍历序列是升序 11 public boolean isValidBST(TreeNode root) { 12 inOrder(root); 13 return isValid; 14 } 15 private TreeNode lastVisited=null; 16 private boolean isValid=true; 17 private void inOrder(TreeNode root) 18 {//中序遍历,若是遇到上次访问节点值比当前根节点大,则invalid并结束 19 if(root!=null) 20 { 21 inOrder(root.left); 22 23 if(lastVisited!=null) 24 { 25 if(lastVisited.val>=root.val) 26 { 27 isValid=false; 28 } 29 } 30 lastVisited=root; 31 32 inOrder(root.right); 33 } 34 } 35 } 36 37 public class Solution { 38 public boolean isValidBST(TreeNode root) { 39 return isBST(root, Long.MIN_VALUE, Long.MAX_VALUE); 40 } 41 42 private boolean isBST(TreeNode root, long min, long max) {//经过前序遍历 43 44 if(root == null) { 45 return true; 46 } 47 48 // check the node's restriction 49 if(!(root.val > min && root.val < max)) { 50 return false; 51 } 52 53 // check left 54 boolean l = isBST(root.left, min, root.val); 55 boolean r = isBST(root.right, root.val, max); 56 57 return (l == true && r == true); 58 } 59 }
最优二叉查找树:给定一个有序序列{xi},i∈[1,n],再给定查找每一个序列值的几率bi以及查找值不存在时落入区间(xi, xi+1),i∈[0,n]的几率ai,全部的ai、bi总和为1。如何构建二叉搜索树使平均查找路径最短?——动态规划(与求矩阵连乘的最少乘法次数很像)
二叉查找树的平衡:普通的二叉查找树虽然平均时间复杂度为O(lgn),但最坏状况下退化为线性链表此时时间复杂度为O(n),所以实际应用中不实用。一般考虑平衡性,如:
5.一、平衡二叉树(亦称平衡二叉查找树、AVL树):每一个节点的左右子树深度最多差1的二叉查找树
注意,平衡二叉树最先是为了改进二叉排序树的性能而考虑平衡性进而提出来的——即AVL树(固然,其平衡性没有理想平衡二叉树要求那么严,不然维护成本过高),因此通常说到平衡二叉树指的是平衡的二叉排序树。
最小平衡二叉树:节点数最少时的平衡二叉树,此时每一个分支节点的左右子树深度都刚好相差1。设高为h的最小平衡二叉树的节点总数为F(h),则F(h)=左子树节点总数+右子树节点总数+1,即F(h)=F(h-1)+F(h-2)+1,F(1)=一、F(2)=2。
5.二、红黑树:是另外一种考虑了平衡性了的二叉查找树。(可参阅: 红黑树原理和算法)
性质:
一、每一个节点为红色或黑色;
二、根节点为黑色;
三、叶节点为黑色(此叶节点指为空NULL的叶节点);
四、红色节点的子节点必定是黑色;
五、一个节点到它每一个同层子孙节点的路径上黑色节点数相同(此条保证了没有一条路径会比其余路径长2倍,故红黑树是相对平衡的BST)。
含有n个节点的红黑树高度最多为 2*ceil( log2(n+1) ),即高为h的红黑树其节点数至少有2h/2-1个,所以最坏时间复杂度为O(lgn)。
复杂度:插入、删除、查找的平均和最坏时间复杂度为O(lgn),效率高。插入、删除节点可能会破坏上述性质,所以须要进行左旋或右旋转操做以维护性质。因为红黑树平衡性要求没有平衡二叉树那么高,所以插入或删除节点的维护代价比后者低。
应用:主要用来存储有序数据,如Java中的TreeMap、TreeSet,C++中STL中的map、set,Linux中的内存管理等就用了红黑树实现。
5.三、B、B+树:它们不是二叉树查找树,但由二叉查找树扩展而来,是多叉的查找树,且增长了一些有利于平衡性的限制。基于内存的B+树实现:
1 package buaa.act.ucar.imtg.index.node.temporal; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import buaa.act.ucar.util.config.ConfigFileParser; 7 8 /** 9 * The implementation of B+-Tree based on the implementation in reference <a>http://en.wikipedia.org/wiki/B%2B_tree</a><br> 10 * <br> 11 * 一个节点的某个key>左孩子节点内全部的key且≤右孩子节点内全部的key。等号只有对于叶节点的父节点成立,也即B+tree的内部节点的key都不一样。 <br> 12 * <br> 13 * 若插入后节点的键的数量超出上阈值1时即进行分裂,一个节点分裂成两个后,对于叶节点来讲后节点的第一个元素的键做为新键复制到父节点、对于内部节点来讲后节点的第一个元素的键移到父节点。<br> 14 * 删除时如有节点合并则合并过程与上述过程相反。<br> 15 * <br> 16 * <br> 17 * note: 启用插入借位(或称旋转)能减小内存占用。然而:<br> 18 * 对于随机写入来讲,不采用插入借位会提升查询性能,由于每一个节点的数据量少了,能减小比较;<br> 19 * 对于升序插入来讲,启用插入借位老是能提升插入、查询、删除性能,对于升序输入来讲,采用size-1:1的分裂方法能进一步提升性能。 20 * 21 * 22 * @author zsm 23 * 24 * @param <K> 25 * @param <V> 26 */ 27 public class BPlusTree<K extends Comparable<K>, V> { 28 29 /** 30 * 树的分支<br> 31 * a) 非根内部节点的孩子数: [ Math.ceil(factor/2), factor ]<br/> 32 * b) 叶子节点的孩子数: [ Math.ceil(factor/2)-1, factor-1 ] 33 */ 34 private int factor; 35 36 private static final int DEFAULT_FACTOR = 5; 37 38 private int MIN_CHILDREN_FOR_INTERNAL; 39 private int MAX_CHILDREN_FOR_INTERNAL; 40 private int MIN_CHILDREN_FOR_LEAF; 41 private int MAX_CHILDREN_FOR_LEAF; 42 43 // 给插入时用 44 private Object[] tmpNewKeys; 45 private Node[] tmpNewPointers; 46 private Object[] tmpNewValues; 47 48 private Node<K, V> root; 49 50 /** 叶节点数据记录总数 */ 51 private int dataCount; 52 53 /** 54 * 待存数据是否有序存入 ,决定了节点的分裂方案:<br> 55 * ASCENDING:分裂后新节点存一个元素 <br> 56 * DESCENDING:分裂后原节点存一个元素<br> 57 * RANDOM:对半分 58 */ 59 public enum InputDataOrder { 60 ASCENDING, DESCENDING, RANDOM 61 } 62 63 private InputDataOrder inputDataOrder; 64 65 public BPlusTree(InputDataOrder inputDataOrder) { 66 this(DEFAULT_FACTOR, inputDataOrder); 67 } 68 69 public BPlusTree(int factor, InputDataOrder inputDataOrder) { 70 if (factor < 3) { 71 System.out.print("order must be greater than 2"); 72 System.exit(0); 73 } 74 75 // System.out.println("factor for tree:" + factor); 76 this.inputDataOrder = inputDataOrder; 77 78 this.factor = factor; 79 80 this.MIN_CHILDREN_FOR_INTERNAL = (this.factor + 1) / 2; 81 this.MAX_CHILDREN_FOR_INTERNAL = this.factor; 82 this.MIN_CHILDREN_FOR_LEAF = this.MIN_CHILDREN_FOR_INTERNAL - 1; 83 this.MAX_CHILDREN_FOR_LEAF = this.MAX_CHILDREN_FOR_INTERNAL - 1; 84 85 // 比容许的最大值多1 86 tmpNewKeys = new Object[MAX_CHILDREN_FOR_INTERNAL]; 87 tmpNewPointers = new Node[MAX_CHILDREN_FOR_INTERNAL + 1]; 88 tmpNewValues = new Object[MAX_CHILDREN_FOR_LEAF + 1]; 89 90 this.root = new LeafNode<K, V>(); 91 this.dataCount = 0; 92 } 93 94 /** 95 * 根据给定的key获取对应的值 96 */ 97 public V get(K key) { 98 return this.root.get(key); 99 } 100 101 /** 102 * 获取指定key范围内的值 103 */ 104 public ArrayList<V> get(K keyStart, K keyEnd) { 105 if (keyStart.compareTo(keyEnd) > 0) { 106 return null; 107 } 108 LeafNode<K, V> leafNodeStart, leafNodeEnd; 109 if (root instanceof LeafNode) {// 说明整个树只有一个节点 110 leafNodeStart = leafNodeEnd = (LeafNode<K, V>) root; 111 } else { 112 leafNodeStart = ((InternalNode<K, V>) root).getLeafNodeByKey(keyStart); 113 leafNodeEnd = ((InternalNode<K, V>) root).getLeafNodeByKey(keyEnd); 114 } 115 116 // 获取结果 117 ArrayList<V> res = new ArrayList<>(); 118 int nodeSize; 119 K tmpK; 120 do { 121 nodeSize = leafNodeStart.size; 122 for (int i = 0; i < nodeSize; i++) { 123 tmpK = (K) leafNodeStart.keys[i]; 124 if (keyStart.compareTo(tmpK) <= 0 && tmpK.compareTo(keyEnd) <= 0) { 125 res.add((V) leafNodeStart.values[i]); 126 } 127 } 128 leafNodeStart = (LeafNode<K, V>) leafNodeStart.next; 129 } while (leafNodeStart != leafNodeEnd.next); 130 return res; 131 } 132 133 /** 134 * 获取指定oid在指定key范围内的值,此方法在B+tree key 为gpstime#oid组合的String类型时 才适用 135 */ 136 public ArrayList<V> get(String oid, K keyStart, K keyEnd) { 137 if (keyStart.compareTo(keyEnd) > 0) { 138 return null; 139 } 140 LeafNode<K, V> leafNodeStart, leafNodeEnd; 141 if (root instanceof LeafNode) {// 说明整个树只有一个节点 142 leafNodeStart = leafNodeEnd = (LeafNode<K, V>) root; 143 } else { 144 leafNodeStart = ((InternalNode<K, V>) root).getLeafNodeByKey(keyStart); 145 leafNodeEnd = ((InternalNode<K, V>) root).getLeafNodeByKey(keyEnd); 146 } 147 148 // 获取结果 149 ArrayList<V> res = new ArrayList<>(); 150 int nodeSize; 151 K tmpK; 152 String tmpOid; 153 do { 154 nodeSize = leafNodeStart.size; 155 for (int i = 0; i < nodeSize; i++) { 156 tmpK = (K) leafNodeStart.keys[i]; 157 tmpOid = tmpK.toString(); 158 // System.out.println("_" + tmpOid); 159 tmpOid = tmpOid.substring(tmpOid.indexOf(ConfigFileParser.bplustree_TagForDivdingGpstimeDevsn) + 1);// 获取oid 160 if (tmpOid.equals(oid) && keyStart.compareTo(tmpK) <= 0 && tmpK.compareTo(keyEnd) <= 0) { 161 res.add((V) leafNodeStart.values[i]); 162 } 163 } 164 leafNodeStart = (LeafNode<K, V>) leafNodeStart.next; 165 } while (leafNodeStart != leafNodeEnd.next); 166 return res; 167 } 168 169 /** 170 * 插入键值对,若键已存在,则更新值 171 */ 172 public void set(K key, V value) { 173 if (key == null) 174 throw new NullPointerException("key must not be null."); 175 176 Node<K, V> node = this.root.insert(key, value); 177 if (node != null) 178 this.root = node; 179 } 180 181 /** 182 * 删除给定的key对应的值 183 */ 184 public void remove(K key) { 185 // TODO Auto-generated method stub 186 Node node = this.root.remove(key); 187 if (node != null) { 188 this.root = node; 189 } 190 } 191 192 /** 获取树的根节点 */ 193 public Node<K, V> getRoot() { 194 return this.root; 195 } 196 197 /** 获取最左边的叶节点 */ 198 public LeafNode<K, V> getLeftestLeafNode() { 199 Node<K, V> node = this.root; 200 while (!(node instanceof LeafNode)) { 201 node = ((InternalNode<K, V>) node).pointers[0]; 202 } 203 return (LeafNode<K, V>) node; 204 } 205 206 /** 获取树中数据记录总数 */ 207 public int getDataCount() { 208 return this.dataCount; 209 } 210 211 /** 212 * 获取全部value 213 */ 214 public List<V> getAllValues() { 215 List<V> res = new ArrayList<>(this.dataCount); 216 LeafNode<K, V> leafNode = getLeftestLeafNode(); 217 while (leafNode != null) { 218 for (int i = 0; i < leafNode.size; i++) { 219 res.add((V) leafNode.values[i]); 220 } 221 leafNode = (LeafNode<K, V>) leafNode.next; 222 } 223 return res; 224 } 225 226 /** 获取树的高度,最少为1 */ 227 public int getHeight() { 228 int height = 1; 229 Node<K, V> node = this.root; 230 while (!(node instanceof LeafNode)) { 231 node = ((InternalNode<K, V>) node).pointers[0]; 232 height++; 233 } 234 return height; 235 } 236 237 /** 打印树结构 */ 238 public void printTree() { 239 this.printTreeFrom(this.root); 240 } 241 242 private void printTreeFrom(Node<K, V> startRoot) { 243 System.out.println("print tree:"); 244 Node<K, V> curNode = null; 245 do { 246 curNode = startRoot; 247 while (curNode != null) { 248 // System.out.print("|"); 249 // for (int i = 0; i < curNode.size; i++) { 250 // System.out.print(curNode.keys[i]); 251 // if (i != curNode.size - 1) { 252 // System.out.print(","); 253 // } 254 // } 255 // System.out.print("| "); 256 System.out.print(curNode); 257 curNode = curNode.next; 258 } 259 if (startRoot instanceof InternalNode) { 260 startRoot = ((InternalNode) startRoot).pointers[0]; 261 } else { 262 startRoot = null; 263 } 264 System.out.println(); 265 } while (startRoot != null); 266 } 267 268 /** 269 * the abstract node definition, define the operation of leaf node and internal node. 270 * 271 * @param <K> 272 * @param <V> 273 */ 274 abstract class Node<K extends Comparable<K>, V> { 275 276 protected Node<K, V> parent; 277 278 protected Node<K, V> previous, next; 279 280 protected Object[] keys; 281 282 /** 283 * 节点中key的个数 284 */ 285 protected int size; 286 287 protected abstract V get(K key); 288 289 /** 290 * if new parent node is created when insert the key-value, the created parent node is returned, otherwise, this method return null.<br> 291 * 若已存在该key则更新值,结束。<br> 292 * 不然找到应该插入的位置。若插入后不会使得当前节点空间上溢则结束;若会上溢则依次看左右相邻<b>兄弟节点</b>是否有空间,有则移一个元素到该兄弟节点并进行必要调整(此操做也称旋转或借位);不然当前节点分裂。内部节点的借位和分裂操做与叶子节点的操做不太同样。 293 * 294 * @param key 295 * @param value 296 * @return 297 */ 298 protected abstract Node<K, V> insert(K key, V value); 299 300 /** 301 * if root is removed, the new root is returned, otherwise, this method return null.<br> 302 * 先删除,而后判断:<br> 303 * 若当前节点是根节点则结束;不然若当前节点的空间未下溢则结束;不然依次看左右相邻<b>兄弟节点</b>是否元素个数大于最小值,如果则借一个元素到当前节点(称旋转或借位),不然依次看与左兄弟节点仍是右兄弟节点合并。内部节点的借位和合并操做与叶子节点的操做不太同样。 <br> 304 * 能够改进:节点合并时存起该丢弃的节点,在节点分裂时不用new新节点而是复用该节点,以节省空间。 305 * 306 * @param key 307 * @param value 308 * @return 309 */ 310 protected abstract Node<K, V> remove(K key); 311 312 @Override 313 public String toString() { 314 StringBuilder nodeKeyInfo = new StringBuilder(); 315 nodeKeyInfo.append("|"); 316 for (int i = 0; i < this.size; i++) { 317 nodeKeyInfo.append(this.keys[i]); 318 if (i != this.size - 1) { 319 nodeKeyInfo.append(","); 320 } 321 } 322 nodeKeyInfo.append("| "); 323 return nodeKeyInfo.toString(); 324 } 325 } 326 327 /** 328 * the internal node which manages the pointers. 329 * 330 * @param <K> 331 * @param <V> 332 */ 333 final class InternalNode<K extends Comparable<K>, V> extends Node<K, V> { 334 private Node<K, V>[] pointers; 335 336 public InternalNode() { 337 this.size = 0; 338 this.pointers = new Node[MAX_CHILDREN_FOR_INTERNAL]; 339 this.keys = new Object[MAX_CHILDREN_FOR_INTERNAL - 1]; 340 this.parent = null; 341 342 this.previous = null; 343 this.next = null; 344 } 345 346 @Override 347 protected V get(K key) { 348 // int i = 0; 349 // for (; i < this.size; i++) { 350 // if (key.compareTo((K) this.keys[i]) < 0) 351 // break; 352 // } 353 // return this.pointers[i].get(key); 354 LeafNode<K, V> tmpNode = getLeafNodeByKey(key); 355 if (tmpNode == null) { 356 return null; 357 } else { 358 return tmpNode.get(key); 359 } 360 } 361 362 @Override 363 protected Node<K, V> insert(K key, V value) { 364 // int i = 0; 365 // for (; i < this.size; i++) { 366 // if (key.compareTo((K) this.keys[i]) < 0) 367 // break; 368 // } 369 // return this.pointers[i].insert(key, value); 370 LeafNode<K, V> tmpNode = getLeafNodeByKey(key); 371 if (tmpNode == null) { 372 return null; 373 } else { 374 return tmpNode.insert(key, value); 375 } 376 } 377 378 @Override 379 protected Node<K, V> remove(K key) { 380 // TODO Auto-generated method stub 381 LeafNode<K, V> tmpNode = getLeafNodeByKey(key); 382 if (tmpNode == null) { 383 return null; 384 } else { 385 return tmpNode.remove(key); 386 } 387 } 388 389 /** 390 * 根据给定的key获取应在的LeafNode,即便该LeafNode没有该key 391 */ 392 public LeafNode<K, V> getLeafNodeByKey(K key) { 393 Node<K, V> tmpNode = this; 394 int i; 395 do { 396 for (i = 0; i < tmpNode.size; i++) { 397 if (key.compareTo((K) tmpNode.keys[i]) < 0) 398 break; 399 } 400 tmpNode = ((InternalNode<K, V>) tmpNode).pointers[i]; 401 } while (tmpNode instanceof InternalNode); 402 return (LeafNode<K, V>) tmpNode; 403 } 404 405 /** 406 * 在当前节点中插入指定的key及其相应左右孩子树。设key应当在当前节点的关键字a、b间,leftChild、rightChild中的任意一个关键字分别为x、y,则有a≤x<key≤y<b 407 * 408 * @return 若树高度增长致使产生新根节点则返回该新根节点,不然返回null 409 */ 410 private Node<K, V> insert(K key, Node<K, V> leftChild, Node<K, V> rightChild) { 411 if (this.size == 0) {// 增长一层 412 // System.out.println("**internal insert " + key + " in 0 of " + this.toString()); 413 this.size++; 414 this.pointers[0] = leftChild; 415 this.pointers[1] = rightChild; 416 this.keys[0] = key; 417 return this; 418 } 419 420 // key应该在的位置 421 int i; 422 for (i = 0; i < this.size; i++) { 423 if (key.compareTo((K) this.keys[i]) < 0) { 424 break; 425 } 426 } 427 // System.out.println("**internal insert " + key + " in " + i + " of " + this.toString()); 428 429 // 未满,直接插入 430 if (this.size + 1 < MAX_CHILDREN_FOR_INTERNAL) { 431 for (int j = this.size; j > i; j--) { 432 this.keys[j] = this.keys[j - 1]; 433 this.pointers[j + 1] = this.pointers[j]; 434 } 435 this.keys[i] = key; 436 this.pointers[i + 1] = rightChild; 437 this.size++; 438 return null; 439 } 440 // 如下分支:插入后会满 441 // 442 else if (this.previous != null && (this.previous.parent == this.parent) 443 && this.previous.size < MAX_CHILDREN_FOR_LEAF) {// 旋转操做:放一个到前一兄弟节点 444 // 找到父节点中分界key的位置 445 Node<K, V> parent = this.parent; 446 K tmpKey = (K) this.keys[0]; 447 int j; 448 for (j = parent.size - 1; j >= 0; j--) { 449 if (tmpKey.compareTo((K) (parent.keys[j])) >= 0) {// 若维护叶节点第一个key等于父节点分界key,则只会= 450 break; 451 } 452 } 453 454 // 把当前节点的一个元素放到目标兄弟节点后在当前节点插入key-value,并更新父节点key 455 InternalNode<K, V> toNode = (InternalNode<K, V>) this.previous; 456 457 // 移动一个节点到前一节点 458 toNode.keys[toNode.size] = parent.keys[j]; 459 toNode.pointers[toNode.size + 1] = this.pointers[0]; 460 this.pointers[0].parent = toNode; 461 toNode.size++; 462 463 // 更新父节点key并在当前节点插入新元素 464 if (i == 0) {// 按理应插入到当前节点首位 465 // 更新父节点key 466 parent.keys[j] = key; 467 // 当前节点插入新元素 468 this.pointers[0] = rightChild; 469 } else { 470 // 更新父节点key 471 parent.keys[j] = this.keys[0]; 472 // 当前节点插入新元素.移掉一个元素到目的节点后,待插元素应放在i-1的位置 473 this.pointers[0] = this.pointers[1]; 474 int insertPos = i - 1; 475 for (int k = 0; k < insertPos; k++) { 476 this.keys[k] = this.keys[k + 1]; 477 this.pointers[k + 1] = this.pointers[k + 2]; 478 } 479 this.keys[insertPos] = key; 480 this.pointers[insertPos + 1] = rightChild; 481 } 482 483 return null; 484 485 } else if (this.next != null && (this.next.parent == this.parent) 486 && this.next.size < MAX_CHILDREN_FOR_LEAF) {// 旋转操做: 放一个到下一兄弟节点 487 488 InternalNode<K, V> toNode = (InternalNode<K, V>) this.next; 489 // 找到父节点中分界key的位置 490 Node<K, V> parent = this.parent; 491 K tmpKey = (K) toNode.keys[0]; 492 int j; 493 for (j = parent.size - 1; j >= 0; j--) { 494 if (tmpKey.compareTo((K) (parent.keys[j])) >= 0) {// 若维护叶节点第一个key等于父节点分界key,则只会= 495 break; 496 } 497 } 498 499 // 腾出首位 500 for (int k = toNode.size; k > 0; k--) { 501 toNode.keys[k] = toNode.keys[k - 1]; 502 toNode.pointers[k + 1] = toNode.pointers[k]; 503 } 504 toNode.pointers[1] = toNode.pointers[0]; 505 toNode.size++; 506 507 // 把当前节点的一个元素放到目标兄弟节点后在当前节点插入key-value,并更新父节点key 508 if (i == this.size) { 509 toNode.keys[0] = parent.keys[j]; 510 toNode.pointers[0] = rightChild; 511 rightChild.parent = toNode; 512 513 parent.keys[j] = key; 514 } else { 515 toNode.keys[0] = parent.keys[j]; 516 toNode.pointers[0] = this.pointers[this.size]; 517 toNode.pointers[0].parent = toNode; 518 519 parent.keys[j] = this.keys[this.size - 1]; 520 521 for (int k = this.size - 1; k > i; k--) { 522 this.keys[k] = this.keys[k - 1]; 523 this.pointers[k + 1] = this.pointers[k]; 524 } 525 this.keys[i] = key; 526 this.pointers[i + 1] = rightChild; 527 } 528 529 return null; 530 531 } else {// 分裂 532 // 已满,须要分裂 533 { 534 // InternalNode<K, V> newNode = new InternalNode<K, V>(); 535 // 536 // int tmpSizeIfInserted = this.size + 1; 537 // // 若是插入后须要被提到父节点的key及其下标,须要确保分裂开的两节点都至少有一个元素 538 // K parentKey = null; 539 // int m = (tmpSizeIfInserted / 2); 540 // switch (inputDataOrder) { 541 // case ASCENDING: 542 // m = tmpSizeIfInserted - 2; 543 // break; 544 // case DESCENDING: 545 // m = 1; 546 // break; 547 // case RANDOM: 548 // default: 549 // m = (tmpSizeIfInserted / 2); 550 // break; 551 // } 552 // 553 // if (i == m) { 554 // parentKey = key; 555 // // 复制到新节点并删除原节点里相应的内容 556 // newNode.pointers[0] = rightChild; 557 // newNode.pointers[0].parent = newNode; 558 // for (int j = m; j < this.size; j++) { 559 // newNode.keys[j - m] = this.keys[j]; 560 // newNode.pointers[j + 1 - m] = this.pointers[j + 1]; 561 // newNode.pointers[j + 1 - m].parent = newNode; 562 // this.keys[j] = null; 563 // this.pointers[j + 1] = null; 564 // newNode.size++; 565 // } 566 // this.size = m; 567 // 568 // } else if (i < m) { 569 // parentKey = (K) this.keys[m - 1]; 570 // // 复制到新节点并删除原节点里相应的内容 571 // newNode.pointers[0] = this.pointers[m]; 572 // newNode.pointers[0].parent = newNode; 573 // for (int j = m; j < this.size; j++) { 574 // newNode.keys[j - m] = this.keys[j]; 575 // newNode.pointers[j + 1 - m] = this.pointers[j + 1]; 576 // newNode.pointers[j + 1 - m].parent = newNode; 577 // this.keys[j] = null; 578 // this.pointers[j + 1] = null; 579 // newNode.size++; 580 // } 581 // this.size = m; 582 // 583 // // 插入新内容到原节点 584 // for (int j = m - 1; j > i; j--) { 585 // this.keys[j] = this.keys[j - 1]; 586 // this.pointers[j + 1] = this.pointers[j]; 587 // } 588 // this.keys[i] = key; 589 // this.pointers[i + 1] = rightChild; 590 // } else { 591 // parentKey = (K) this.keys[m]; 592 // // 复制到新节点并删除原节点里相应的内容 593 // newNode.pointers[0] = this.pointers[m + 1]; 594 // newNode.pointers[0].parent = newNode; 595 // for (int j = m + 1; j < this.size; j++) { 596 // if (j == i) {// 复制插入的新内容 597 // newNode.keys[newNode.size] = key; 598 // newNode.pointers[newNode.size + 1] = rightChild; 599 // newNode.size++; 600 // } 601 // // 复制原节点的内容 602 // newNode.keys[newNode.size] = this.keys[j]; 603 // newNode.pointers[newNode.size + 1] = this.pointers[j + 1]; 604 // newNode.pointers[newNode.size + 1].parent = newNode; 605 // this.keys[j] = null; 606 // this.pointers[j + 1] = null; 607 // newNode.size++; 608 // } 609 // if (i == this.size) {// 复制插入的新内容 610 // newNode.keys[newNode.size] = key; 611 // newNode.pointers[newNode.size + 1] = rightChild; 612 // newNode.size++; 613 // } 614 // this.size = m; 615 // } 616 // 617 // if (this.parent == null) { 618 // this.parent = new InternalNode<K, V>(); 619 // } 620 // newNode.parent = this.parent; 621 // 622 // // 更新节点间的相邻关系 623 // newNode.next = this.next; 624 // newNode.previous = this; 625 // if (this.next != null) { 626 // this.next.previous = newNode; 627 // } 628 // this.next = newNode; 629 // 630 // return ((InternalNode<K, V>) this.parent).insert(parentKey, this, newNode); 631 } 632 633 // 原实现 634 System.arraycopy(this.keys, 0, tmpNewKeys, 0, i); 635 tmpNewKeys[i] = key; 636 System.arraycopy(this.keys, i, tmpNewKeys, i + 1, this.size - i); 637 638 System.arraycopy(this.pointers, 0, tmpNewPointers, 0, i + 1); 639 tmpNewPointers[i + 1] = rightChild; 640 System.arraycopy(this.pointers, i + 1, tmpNewPointers, i + 2, this.size - i); 641 642 this.size++; 643 644 // 要被提到父节点的key的下标,须要确保分裂开的两节点都至少有一个元素 645 int m = (this.size / 2); 646 switch (inputDataOrder) { 647 case ASCENDING: 648 m = this.size - 2; 649 break; 650 case DESCENDING: 651 m = 1; 652 break; 653 case RANDOM: 654 default: 655 m = (this.size / 2); 656 break; 657 } 658 659 // split the internal node 660 InternalNode<K, V> newNode = new InternalNode<K, V>(); 661 662 newNode.size = this.size - m - 1; 663 System.arraycopy(tmpNewKeys, m + 1, newNode.keys, 0, newNode.size); 664 System.arraycopy(tmpNewPointers, m + 1, newNode.pointers, 0, newNode.size + 1); 665 666 // reset the children's parent to the new node. 667 for (int j = 0; j <= newNode.size; j++) { 668 newNode.pointers[j].parent = newNode; 669 } 670 671 this.size = m; 672 673 System.arraycopy(tmpNewKeys, 0, this.keys, 0, m); 674 System.arraycopy(tmpNewPointers, 0, this.pointers, 0, m + 1); 675 676 if (this.parent == null) { 677 this.parent = new InternalNode<K, V>(); 678 } 679 newNode.parent = this.parent; 680 681 // 更新节点间的相邻关系 682 newNode.next = this.next; 683 newNode.previous = this; 684 if (this.next != null) { 685 this.next.previous = newNode; 686 } 687 this.next = newNode; 688 689 // tmpNewKeys[m]做为新key插入父节点,此key在分裂后的两个节点中都不存在 690 return ((InternalNode<K, V>) this.parent).insert((K) tmpNewKeys[m], this, newNode); 691 } 692 } 693 694 /** 695 * 下层节点在触发合并操做时才会进入此方法。rightChild丢弃、key删掉 696 * 697 * @return 若树高度下降致使产生新根节点则返回该新根节点,不然返回null 698 */ 699 private Node<K, V> remove(K key, Node<K, V> leftChil3d, Node<K, V> rightCh6ild) { 700 // TODO Auto-generated method stub 701 702 // 找key的位置 703 int i; 704 for (i = 0; i < this.size; i++) { 705 if (key.compareTo((K) this.keys[i]) == 0) { 706 break; 707 } 708 } 709 710 // 没找到,结束 711 if (i == this.size) { 712 return null; 713 } 714 715 // 找到,删除key对应的记录、指向合并后被丢弃的子节点(即rightChild也即this.pointers[i + 1])的指针置空 716 for (; i < this.size - 1; i++) { 717 this.keys[i] = this.keys[i + 1]; 718 this.pointers[i + 1] = this.pointers[i + 2]; 719 } 720 // System.out.println("**internal remove " + key + " in " + i + " of " + this.toString()); 721 this.keys[this.size - 1] = null; 722 this.pointers[this.size] = null; 723 this.size--; 724 725 /* 如下进行调整 */ 726 727 // 当前层只有一个节点的状况,为根节点 728 if (this.previous == null && this.next == null) { 729 if (this.size == 0) {// 减小一层 730 Node<K, V> newRoot = (Node<K, V>) (this.pointers[0]); 731 newRoot.parent = null; 732 return newRoot; 733 } else { 734 return null; 735 } 736 } 737 // 如下分支:当前节点有兄弟节点 738 739 else if (this.size >= (MIN_CHILDREN_FOR_INTERNAL - 1)) {// 无须借位、合并,结束 740 return null; 741 } 742 // 如下分支:当前节点有兄弟节点,且删后当前节点的键数为(MIN_CHILDREN_FOR_INTERNAL - 2),须要借位或合并 743 744 else if (this.previous != null && (this.previous.parent == this.parent) 745 && this.previous.size > (MIN_CHILDREN_FOR_INTERNAL - 1)) {// 从前一兄弟节点借一个元素 746 InternalNode<K, V> borrowedNode = (InternalNode<K, V>) this.previous; 747 748 /** 设this和previous在parent的分界键为key_parent,previous的最后一键和指针为key_last、pointer_last,则将key_parent、pointer_last做为新元素插入到this首位且将key_last替代parent的key_parent */ 749 int j; 750 // 后挪空出首位 751 for (j = this.size; j > 0; j--) { 752 this.keys[j] = this.keys[j - 1]; 753 this.pointers[j + 1] = this.pointers[j]; 754 } 755 this.pointers[1] = this.pointers[0]; 756 757 // 找出父节点key所在位置 758 Node<K, V> parent = this.parent; 759 K tmpKey = (this.size == 0) ? key : (K) this.keys[1]; 760 for (j = parent.size - 1; j >= 0; j--) { 761 if (tmpKey.compareTo((K) (parent.keys[j])) > 0) { 762 break; 763 } 764 } 765 766 // 借位操做 767 this.keys[0] = parent.keys[j]; 768 this.pointers[0] = borrowedNode.pointers[borrowedNode.size]; 769 this.pointers[0].parent = this; 770 this.size++; 771 parent.keys[j] = borrowedNode.keys[borrowedNode.size - 1]; 772 borrowedNode.keys[borrowedNode.size - 1] = null; 773 borrowedNode.pointers[borrowedNode.size] = null; 774 borrowedNode.size--; 775 776 return null; 777 778 } else if (this.next != null && (this.next.parent == this.parent) 779 && this.next.size > (MIN_CHILDREN_FOR_INTERNAL - 1)) {// 从后一个兄弟节点借一个元素 780 InternalNode<K, V> borrowedNode = (InternalNode<K, V>) this.next; 781 782 // 找出父节点key所在位置 783 int j; 784 Node<K, V> parent = this.parent; 785 K tmpKey = (K) borrowedNode.keys[0]; 786 for (j = parent.size - 1; j >= 0; j--) { 787 if (tmpKey.compareTo((K) (parent.keys[j])) > 0) { 788 break; 789 } 790 } 791 792 // 借位操做 793 this.keys[this.size] = parent.keys[j]; 794 this.pointers[this.size + 1] = borrowedNode.pointers[0]; 795 this.pointers[this.size + 1].parent = this; 796 this.size++; 797 parent.keys[j] = borrowedNode.keys[0]; 798 799 for (j = 0; j < borrowedNode.size - 1; j++) { 800 borrowedNode.keys[j] = borrowedNode.keys[j + 1]; 801 borrowedNode.pointers[j] = borrowedNode.pointers[j + 1]; 802 } 803 borrowedNode.pointers[j] = borrowedNode.pointers[j + 1]; 804 borrowedNode.keys[borrowedNode.size - 1] = null; 805 borrowedNode.pointers[borrowedNode.size] = null; 806 borrowedNode.size--; 807 808 return null; 809 810 } else if (this.previous != null && (this.previous.parent == this.parent) 811 && this.previous.size == (MIN_CHILDREN_FOR_INTERNAL - 1)) {// 与前一兄弟节点合并。(其实只会=,不会<) 812 // parent中的分界key复制到前一节点末尾后当前节点内容复制到前一节点 813 // 合并后目标节点的size为(MIN_CHILDREN_FOR_INTERNAL - 1) +1+ (MIN_CHILDREN_FOR_INTERNAL - 2) 814 815 InternalNode<K, V> previous = (InternalNode<K, V>) this.previous; 816 817 // 找出父节点分界key所在位置 818 Node<K, V> parent = this.parent; 819 K tmpKey = this.size == 0 ? key : (K) this.keys[0]; 820 int j; 821 for (j = parent.size - 1; j >= 0; j--) { 822 if (tmpKey.compareTo((K) (parent.keys[j])) > 0) { 823 break; 824 } 825 } 826 827 // 合并 828 previous.keys[previous.size] = parent.keys[j]; 829 previous.pointers[previous.size + 1] = this.pointers[0]; 830 this.pointers[0].parent = previous; 831 this.pointers[0] = null;// 复制过去后清空本节点的该元素 832 previous.size++; 833 for (int k = 0; k < this.size; k++) { 834 previous.keys[previous.size + k] = this.keys[k]; 835 previous.pointers[previous.size + k + 1] = this.pointers[k + 1]; 836 this.pointers[k + 1].parent = previous; 837 838 this.keys[k] = null;// 复制过去后清空本节点的该元素,下同 839 this.pointers[k + 1] = null; 840 } 841 previous.size += this.size; 842 this.size = 0;// 复制过去后清空本节点 843 844 // 更新节点相邻关系 845 previous.next = this.next; 846 if (this.next != null) { 847 this.next.previous = previous; 848 } 849 this.parent = null; 850 this.previous = null; 851 this.next = null; 852 853 return ((InternalNode<K, V>) previous.parent).remove((K) parent.keys[j], previous, this); 854 } else if (this.next != null && (this.next.parent == this.parent) 855 && this.next.size == (MIN_CHILDREN_FOR_INTERNAL - 1)) {// 与后一兄弟节点合并。(其实只会=,不会<) 856 // parent中的分界key复制到当前节点末尾后后一节点的内容复制到当前节点 857 // 合并后目标节点的size为(MIN_CHILDREN_FOR_INTERNAL - 1) +1+ (MIN_CHILDREN_FOR_INTERNAL - 2) 858 859 InternalNode<K, V> next = (InternalNode<K, V>) this.next; 860 861 // 找出父节点分界key所在位置 862 Node<K, V> parent = next.parent; 863 K tmpKey = (K) next.keys[0]; 864 int j; 865 for (j = parent.size - 1; j >= 0; j--) { 866 if (tmpKey.compareTo((K) (parent.keys[j])) > 0) { 867 break; 868 } 869 } 870 871 // 合并 872 this.keys[this.size] = parent.keys[j]; 873 this.pointers[this.size + 1] = next.pointers[0]; 874 next.pointers[0].parent = this; 875 next.pointers[0] = null;// 复制过去后清空本节点的该元素 876 this.size++; 877 for (int k = 0; k < next.size; k++) { 878 this.keys[this.size + k] = next.keys[k]; 879 this.pointers[this.size + k + 1] = next.pointers[k + 1]; 880 next.pointers[k + 1].parent = this; 881 882 next.keys[k] = null;// 复制过去后清空本节点的该元素,下同 883 next.pointers[k + 1] = null; 884 } 885 this.size += next.size; 886 next.size = 0;// 复制过去后清空本节点的该元素 887 888 // 更新节点相邻关系 889 this.next = next.next; 890 if (next.next != null) { 891 next.next.previous = this; 892 } 893 next.parent = null; 894 next.previous = null; 895 next.next = null; 896 897 return ((InternalNode<K, V>) this.parent).remove((K) parent.keys[j], this, next); 898 } else {// 永远到不了这 899 System.err.println("wrong in internal node remove."); 900 return null; 901 } 902 } 903 } 904 905 /** 906 * leaf node, store the keys and actual values. 907 * 908 * @param <K> 909 * @param <V> 910 */ 911 final class LeafNode<K extends Comparable<K>, V> extends Node<K, V> { 912 private Object[] values; 913 914 public LeafNode() { 915 this.size = 0; 916 this.keys = new Object[MAX_CHILDREN_FOR_LEAF]; 917 this.values = new Object[MAX_CHILDREN_FOR_LEAF]; 918 this.parent = null; 919 920 this.previous = null; 921 this.next = null; 922 } 923 924 @Override 925 protected V get(K key) { 926 // two branch search 927 if (this.size == 0) { 928 return null; 929 } 930 931 int s = 0, e = this.size - 1; 932 int m = -1; 933 K mKey = null; 934 boolean isFind = false; 935 while (s <= e) { 936 m = (s + e) / 2; 937 mKey = (K) this.keys[m]; 938 if (key.compareTo(mKey) == 0) { 939 isFind = true; 940 break; 941 } else if (key.compareTo(mKey) > 0) { 942 s = m + 1; 943 } else { 944 e = m - 1; 945 } 946 } 947 return isFind ? ((V) this.values[m]) : null; 948 } 949 950 @Override 951 protected Node<K, V> insert(K key, V value) { 952 int i = 0; 953 for (; i < this.size; i++) { 954 K curKey = (K) this.keys[i]; 955 if (curKey.compareTo(key) == 0) {// key已存在,更新值 956 this.values[i] = value; 957 return null; 958 } 959 if (curKey.compareTo(key) > 0) 960 break; 961 } 962 963 dataCount++; 964 // 如下分支:key不存在,插入新key-value 965 966 // 未满,直接插入 967 if (this.size + 1 <= MAX_CHILDREN_FOR_LEAF) { 968 for (int j = this.size; j > i; j--) { 969 this.keys[j] = this.keys[j - 1]; 970 this.values[j] = this.values[j - 1]; 971 } 972 this.keys[i] = key; 973 this.values[i] = value; 974 this.size++; 975 return null; 976 } 977 // 如下分支:插入后会满 978 // 979 else if (this.previous != null && (this.previous.parent == this.parent) 980 && this.previous.size < MAX_CHILDREN_FOR_LEAF) {// 旋转操做:放一个到前一兄弟节点 981 // 找到父节点中分界key的位置 982 Node<K, V> parent = this.parent; 983 K tmpKey = (K) this.keys[0]; 984 int j; 985 for (j = parent.size - 1; j >= 0; j--) { 986 if (tmpKey.compareTo((K) (parent.keys[j])) >= 0) {// 若维护叶节点第一个key等于父节点分界key,则只会= 987 break; 988 } 989 } 990 991 // 把当前节点的一个元素放到目标兄弟节点后在当前节点插入key-value,并更新父节点key 992 LeafNode<K, V> toNode = (LeafNode<K, V>) this.previous; 993 if (i == 0) {// 按理应插入到当前节点首位 994 toNode.keys[toNode.size] = key; 995 toNode.values[toNode.size] = value; 996 toNode.size++; 997 } else { 998 toNode.keys[toNode.size] = this.keys[0]; 999 toNode.values[toNode.size] = this.values[0]; 1000 toNode.size++; 1001 1002 // 移掉一个元素到目的节点后,待插元素应放在i-1的位置 1003 int insertPos = i - 1; 1004 for (int k = 0; k < insertPos; k++) { 1005 this.keys[k] = this.keys[k + 1]; 1006 this.values[k] = this.values[k + 1]; 1007 } 1008 this.keys[insertPos] = key; 1009 this.values[insertPos] = value; 1010 } 1011 1012 // 更新它们的父节点的分界key 1013 parent.keys[j] = this.keys[0]; 1014 1015 return null; 1016 1017 } else if (this.next != null && (this.next.parent == this.parent) 1018 && this.next.size < MAX_CHILDREN_FOR_LEAF) {// 旋转操做: 放一个到下一兄弟节点 1019 LeafNode<K, V> toNode = (LeafNode<K, V>) this.next; 1020 // 找到父节点中分界key的位置 1021 Node<K, V> parent = this.parent; 1022 K tmpKey = (K) toNode.keys[0]; 1023 int j; 1024 for (j = parent.size - 1; j >= 0; j--) { 1025 if (tmpKey.compareTo((K) (parent.keys[j])) >= 0) {// 若维护叶节点第一个key等于父节点分界key,则只会= 1026 break; 1027 } 1028 } 1029 1030 // 腾出首位 1031 for (int k = toNode.size; k > 0; k--) { 1032 toNode.keys[k] = toNode.keys[k - 1]; 1033 toNode.values[k] = toNode.values[k - 1]; 1034 } 1035 toNode.size++; 1036 1037 // 把当前节点的一个元素放到目标兄弟节点后在当前节点插入key-value,并更新父节点key 1038 if (i == this.size) { 1039 toNode.keys[0] = key; 1040 toNode.values[0] = value; 1041 } else { 1042 toNode.keys[0] = this.keys[this.size - 1]; 1043 toNode.values[0] = this.values[this.size - 1]; 1044 1045 for (int k = this.size - 1; k > i; k--) { 1046 this.keys[k] = this.keys[k - 1]; 1047 this.values[k] = this.values[k - 1]; 1048 } 1049 this.keys[i] = key; 1050 this.values[i] = value; 1051 } 1052 // 更新它们的父节点的分界key 1053 parent.keys[j] = toNode.keys[0]; 1054 1055 return null; 1056 1057 } else {// 进行分裂 1058 1059 { 1060 // LeafNode<K, V> newNode = new LeafNode<K, V>(); 1061 // int tmpSizeIfInserted = this.size + 1; 1062 // // 若是插入后须要被提到父节点的key及其下标,须要确保分裂开的两节点都至少有一个元素 1063 // K parentKey = null; 1064 // int m = (tmpSizeIfInserted / 2); 1065 // switch (inputDataOrder) { 1066 // case ASCENDING: 1067 // m = tmpSizeIfInserted - 1; 1068 // break; 1069 // case DESCENDING: 1070 // m = 1; 1071 // break; 1072 // case RANDOM: 1073 // default: 1074 // m = (tmpSizeIfInserted / 2); 1075 // break; 1076 // } 1077 // 1078 // if (i == m) { 1079 // parentKey = key; 1080 // // 复制到新节点并删除原节点里相应的内容 1081 // newNode.keys[0] = key; 1082 // newNode.values[0] = value; 1083 // newNode.size++; 1084 // for (int j = m; j < this.size; j++) { 1085 // newNode.keys[j - m + 1] = this.keys[j]; 1086 // newNode.values[j - m + 1] = this.values[j]; 1087 // this.keys[j] = null; 1088 // this.values[j] = null; 1089 // newNode.size++; 1090 // } 1091 // this.size = m; 1092 // 1093 // } else if (i < m) { 1094 // parentKey = (K) this.keys[m - 1]; 1095 // // 复制到新节点并删除原节点里相应的内容 1096 // for (int j = m - 1; j < this.size; j++) { 1097 // newNode.keys[j - m + 1] = this.keys[j]; 1098 // newNode.values[j - m + 1] = this.values[j]; 1099 // this.keys[j] = null; 1100 // this.values[j] = null; 1101 // newNode.size++; 1102 // } 1103 // this.size = m; 1104 // 1105 // // 插入新内容到原节点 1106 // for (int j = m - 1; j > i; j--) { 1107 // this.keys[j] = this.keys[j - 1]; 1108 // this.values[j] = this.values[j - 1]; 1109 // } 1110 // this.keys[i] = key; 1111 // this.values[i] = value; 1112 // } else { 1113 // parentKey = (K) this.keys[m]; 1114 // // 复制到新节点并删除原节点里相应的内容 1115 // for (int j = m; j < this.size; j++) { 1116 // if (j == i) {// 复制插入的新内容 1117 // newNode.keys[newNode.size] = key; 1118 // newNode.values[newNode.size] = value; 1119 // newNode.size++; 1120 // } 1121 // // 复制原节点的内容 1122 // newNode.keys[newNode.size] = this.keys[j]; 1123 // newNode.values[newNode.size] = this.values[j]; 1124 // this.keys[j] = null; 1125 // this.values[j] = null; 1126 // newNode.size++; 1127 // } 1128 // if (i == this.size) {// 复制插入的新内容 1129 // newNode.keys[newNode.size] = key; 1130 // newNode.values[newNode.size] = value; 1131 // newNode.size++; 1132 // } 1133 // this.size = m; 1134 // } 1135 // if (this.parent == null) {// 只有在刚开始只有一个叶节点且叶节点已满时才成立 1136 // this.parent = new InternalNode<K, V>(); 1137 // } 1138 // newNode.parent = this.parent; 1139 // 1140 // // 更新叶节点的相邻关系 1141 // newNode.next = this.next; 1142 // newNode.previous = this; 1143 // if (this.next != null) { 1144 // this.next.previous = newNode; 1145 // } 1146 // this.next = newNode; 1147 // 1148 // return ((InternalNode<K, V>) this.parent).insert(parentKey, this, newNode); 1149 } 1150 1151 // 原实现 1152 System.arraycopy(this.keys, 0, tmpNewKeys, 0, i); 1153 tmpNewKeys[i] = key; 1154 System.arraycopy(this.keys, i, tmpNewKeys, i + 1, this.size - i); 1155 1156 System.arraycopy(this.values, 0, tmpNewValues, 0, i); 1157 tmpNewValues[i] = value; 1158 System.arraycopy(this.values, i, tmpNewValues, i + 1, this.size - i); 1159 1160 this.size++; 1161 1162 // need split this node 1163 int m = this.size / 2; 1164 switch (inputDataOrder) { 1165 case ASCENDING: 1166 m = this.size - 1; 1167 break; 1168 case DESCENDING: 1169 m = 1; 1170 break; 1171 case RANDOM: 1172 default: 1173 m = (this.size / 2); 1174 break; 1175 } 1176 1177 LeafNode<K, V> newNode = new LeafNode<K, V>(); 1178 newNode.size = this.size - m; 1179 System.arraycopy(tmpNewKeys, m, newNode.keys, 0, newNode.size); 1180 System.arraycopy(tmpNewValues, m, newNode.values, 0, newNode.size); 1181 1182 this.size = m; 1183 System.arraycopy(tmpNewKeys, 0, this.keys, 0, m); 1184 System.arraycopy(tmpNewValues, 0, this.values, 0, m); 1185 1186 if (this.parent == null) {// 只有在刚开始只有一个叶节点且叶节点已满时才成立 1187 this.parent = new InternalNode<K, V>(); 1188 } 1189 newNode.parent = this.parent; 1190 1191 // 更新叶节点的相邻关系 1192 newNode.next = this.next; 1193 newNode.previous = this; 1194 if (this.next != null) { 1195 this.next.previous = newNode; 1196 } 1197 this.next = newNode; 1198 1199 // 清理无用引用,使GC能回收 1200 1201 // tmpNewKeys[m]做为新key插入父节点,此key也做为分裂后后节点的第一个元素 1202 return ((InternalNode<K, V>) this.parent).insert((K) newNode.keys[0], this, newNode); 1203 } 1204 } 1205 1206 @Override 1207 protected Node<K, V> remove(K key) { 1208 // TODO Auto-generated method stub 1209 1210 // 查找key的位置 1211 int i; 1212 for (i = 0; i < this.size; i++) { 1213 if (key.compareTo((K) this.keys[i]) == 0) { 1214 break; 1215 } 1216 } 1217 1218 // 没找到,结束 1219 if (i == this.size) { 1220 return null; 1221 } 1222 1223 // 找到,删除key对应的记录 1224 for (int j = i; j < this.size - 1; j++) { 1225 this.keys[j] = this.keys[j + 1]; 1226 this.values[j] = this.values[j + 1]; 1227 } 1228 // System.out.println("**leaf remove " + key + " in " + i + " of " + this.toString()); 1229 this.keys[this.size - 1] = null; 1230 this.values[this.size - 1] = null; 1231 this.size--; 1232 1233 dataCount--; 1234 1235 /* 如下进行调整 */ 1236 1237 // 树只有此叶节点,无须借位、合并,结束 1238 if (this.parent == null) { 1239 return null; 1240 } 1241 // 且 删后记录数很多于一半,无需借位、合并,结束 1242 else if (this.size >= MIN_CHILDREN_FOR_LEAF) { 1243 if (i == 0) {// 可选操做:删除了第一个元素,所以须要维持叶节点第一个key与父节点的一个key同样 1244 Node<K, V> parent = this.parent; 1245 K tmpKey = (K) this.keys[0]; 1246 for (int j = parent.size - 1; j >= 0; j--) { 1247 if (tmpKey.compareTo((K) (parent.keys[j])) >= 0) {// 只会> 1248 parent.keys[j] = this.keys[0]; 1249 break; 1250 } 1251 } 1252 } 1253 return null; 1254 } 1255 // 如下分支:有兄弟节点,且删后节点的键数为MIN_CHILDREN_FOR_LEAF-1,须要借位或合并:优先尝试借位,借位不成再合并。注意只有兄弟节点间才能借位或合并 1256 1257 else if (this.previous != null && (this.previous.parent == this.parent) 1258 && this.previous.size > MIN_CHILDREN_FOR_LEAF) {// 从前一兄弟节点借一个元素 1259 1260 LeafNode<K, V> borrowedNode = (LeafNode<K, V>) this.previous; 1261 1262 // 取上节点最后一个元素放到当前节点的第一个位置 1263 for (int j = this.size; j > 0; j--) { 1264 this.keys[j] = this.keys[j - 1]; 1265 this.values[j] = this.values[j - 1]; 1266 } 1267 this.keys[0] = borrowedNode.keys[borrowedNode.size - 1]; 1268 this.values[0] = borrowedNode.values[borrowedNode.size - 1]; 1269 this.size++; 1270 borrowedNode.keys[borrowedNode.size - 1] = null; 1271 borrowedNode.values[borrowedNode.size - 1] = null; 1272 borrowedNode.size--; 1273 1274 // 可选操做:更新父节点的key为借来的元素的key 1275 Node<K, V> parent = this.parent; 1276 K tmpKey = (this.size == 1) ? key : (K) this.keys[1]; 1277 for (int j = parent.size - 1; j >= 0; j--) { 1278 if (tmpKey.compareTo((K) (parent.keys[j])) >= 0) {// 若维护叶节点第一个key等于父节点分界key,则只会= 1279 parent.keys[j] = this.keys[0]; 1280 break; 1281 } 1282 } 1283 return null; 1284 1285 } else if (this.next != null && (this.next.parent == this.parent) 1286 && this.next.size > MIN_CHILDREN_FOR_LEAF) {// 从后一兄弟节点借一个元素 1287 1288 LeafNode<K, V> borrowedNode = (LeafNode<K, V>) this.next; 1289 1290 // 取下节点的第一个元素放到当前节点的最后一个位置 1291 this.keys[this.size] = borrowedNode.keys[0]; 1292 this.values[this.size] = borrowedNode.values[0]; 1293 this.size++; 1294 for (int j = 0, len = borrowedNode.size - 1; j < len; j++) { 1295 borrowedNode.keys[j] = borrowedNode.keys[j + 1]; 1296 borrowedNode.values[j] = borrowedNode.values[j + 1]; 1297 } 1298 borrowedNode.keys[borrowedNode.size - 1] = null; 1299 borrowedNode.values[borrowedNode.size - 1] = null; 1300 borrowedNode.size--; 1301 1302 // 可选操做:更新父节点的key为被借节点的新首元素 1303 Node<K, V> parent = this.parent; 1304 K tmpKey = (K) this.keys[this.size - 1]; 1305 for (int j = parent.size - 1; j >= 0; j--) { 1306 if ((tmpKey).compareTo((K) parent.keys[j]) >= 0) {// 若维护叶节点第一个key等于父节点分界key,则只会= 1307 parent.keys[j] = borrowedNode.keys[0]; 1308 break; 1309 } 1310 } 1311 return null; 1312 1313 } else if (this.previous != null && (this.previous.parent == this.parent) 1314 && this.previous.size == MIN_CHILDREN_FOR_LEAF) {// 与前一兄弟节点合并。(其实只会=,不会<) 1315 // 找出父节点分界key所在位置 1316 K dividKey = this.size == 0 ? key : (K) this.keys[0]; 1317 1318 // 当前节点的内容复制到前一节点,合并后目标节点的size为MIN_CHILDREN_FOR_LEAF + (MIN_CHILDREN_FOR_LEAF-1) 1319 LeafNode<K, V> previous = (LeafNode<K, V>) this.previous; 1320 for (int j = 0; j < this.size; j++) { 1321 previous.keys[previous.size + j] = this.keys[j]; 1322 previous.values[previous.size + j] = this.values[j]; 1323 1324 this.keys[j] = null;// 复制过去后清空本节点的该元素,下同 1325 this.values[j] = null; 1326 } 1327 previous.size += this.size; 1328 this.size = 0;// 复制过去后清空本节点的该元素 1329 1330 // 更新叶节点相邻关系 1331 previous.next = this.next; 1332 if (this.next != null) { 1333 this.next.previous = previous; 1334 } 1335 this.parent = null; 1336 this.previous = null; 1337 this.next = null; 1338 1339 // key及父节点中指向当前节点的poniter会在父节点执行删除方法时被覆盖,从而当前节点被删除 1340 return ((InternalNode<K, V>) previous.parent).remove(dividKey, previous, this); 1341 1342 } else if (this.next != null && (this.next.parent == this.parent) 1343 && this.next.size == MIN_CHILDREN_FOR_LEAF) {// 与后一兄弟节点合并。(其实只会=,不会<) 1344 // 找出父节点分界key所在位置 1345 K dividKey = (K) next.keys[0]; 1346 1347 // 后一节点的内容复制到当前节点,合并后目标节点的size为MIN_CHILDREN_FOR_LEAF + (MIN_CHILDREN_FOR_LEAF-1) 1348 LeafNode<K, V> next = (LeafNode<K, V>) this.next; 1349 for (int j = 0; j < next.size; j++) { 1350 this.keys[this.size + j] = next.keys[j]; 1351 this.values[this.size + j] = next.values[j]; 1352 1353 next.keys[j] = null;// 复制过去后清空本节点的该元素,下同 1354 next.values[j] = null; 1355 } 1356 this.size += next.size; 1357 next.size = 0;// 复制过去后清空本节点的该元素 1358 1359 // 更新叶节点相邻关系 1360 this.next = next.next; 1361 if (next.next != null) { 1362 next.next.previous = this; 1363 } 1364 next.parent = null; 1365 next.previous = null; 1366 next.next = null; 1367 1368 return ((InternalNode<K, V>) this.parent).remove(dividKey, this, next); 1369 } else {// 永远到不了这 1370 System.err.println("wrong in leaf node remove."); 1371 return null; 1372 } 1373 } 1374 } 1375 }
1 package buaa.act.ucar.imtg.index.node.temporal; 2 3 import java.lang.management.ManagementFactory; 4 import java.lang.management.MemoryMXBean; 5 import java.lang.management.MemoryUsage; 6 import java.text.SimpleDateFormat; 7 import java.util.Date; 8 import java.util.HashMap; 9 import java.util.Map; 10 import java.util.Random; 11 12 import buaa.act.ucar.imtg.index.node.temporal.BPlusTree.InputDataOrder; 13 import scala.collection.generic.BitOperations.Int; 14 15 /** 16 * @author zsm 17 * @date 2017年1月11日 上午11:24:58 18 */ 19 public class BPlusTreeTest { 20 public static void main(String[] args) { 21 BPlusTree<Integer, Integer> bPlusTree = new BPlusTree<>(5, InputDataOrder.RANDOM); 22 for (int i = 0; i < 100; i++) { 23 bPlusTree.set(i, i); 24 } 25 bPlusTree.remove(4); 26 bPlusTree.printTree(); 27 System.out.println(bPlusTree.getAllValues()); 28 } 29 30 public static void ma3in(String[] args) { 31 MemoryMXBean memorymbean = ManagementFactory.getMemoryMXBean(); 32 // memorymbean.setVerbose(true); 33 Runtime myRuntime = Runtime.getRuntime(); 34 35 long firinit, firused, fircommited, firmax; 36 long sedmax, sedtotal, sedfree, sedused; 37 double rad = 1024 * 1024.0; 38 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss"); 39 Date date; 40 MemoryUsage usage; 41 42 BPlusTree<String, Integer> tree = new BPlusTree<>(5, InputDataOrder.RANDOM); 43 for (int j = 0; j < 60000; j++) { 44 for (int i = 10_000_000; i > 0; i--) { 45 // tree.set(i + "", i); 46 } 47 48 usage = memorymbean.getHeapMemoryUsage(); 49 date = new Date(); 50 firinit = usage.getInit(); 51 firused = usage.getUsed(); 52 fircommited = usage.getCommitted(); 53 firmax = usage.getMax(); 54 55 sedmax = myRuntime.maxMemory(); 56 sedtotal = myRuntime.totalMemory(); 57 sedfree = myRuntime.freeMemory(); 58 sedused = sedtotal - sedfree; 59 60 System.out.printf( 61 "by MemoryUsage: %s init(%dB≈%.4fMB), used(%dB≈%.4fMB), commited(%dB≈%.4fMB), max(%dB≈%.4fMB)\n", 62 simpleDateFormat.format(date), firinit, firinit / rad, firused, firused / rad, fircommited, 63 fircommited / rad, firmax, firmax / rad); 64 65 System.out.printf( 66 "by Runtime: %s free(%dB≈%.4fMB), used(%dB≈%.4fMB), total(%dB≈%.4fMB), max(%dB≈%.4fMB)\n", 67 simpleDateFormat.format(date), sedfree, sedfree / rad, sedused, sedused / rad, sedtotal, 68 sedtotal / rad, sedmax, sedmax / rad); 69 System.out.println(); 70 try { 71 Thread.sleep(4000); 72 } catch (InterruptedException e) { 73 // TODO Auto-generated catch block 74 e.printStackTrace(); 75 } 76 } 77 78 // System.err.println("add:"); 79 // for (int i = 1; i <= 41; i++) { 80 // tree.set(i, i); 81 // tree.printTree(tree.getRoot()); 82 // } 83 // System.out.println("height:" + tree.getHeight()); 84 // tree.printTree(tree.getRoot()); 85 // 86 // System.err.println("remove:"); 87 // tree.remove(21); 88 // tree.printTree(tree.getRoot()); 89 // tree.remove(22); 90 // tree.printTree(tree.getRoot()); 91 // tree.remove(23); 92 // tree.printTree(tree.getRoot()); 93 94 // test2(); 95 } 96 97 public static int getRandom(int min, int max, boolean isMaxInclude) { 98 return new Random().nextInt(max - min + (isMaxInclude ? 1 : 0)) + min; 99 } 100 101 /** 随机产生数据,并进行查询、删除 */ 102 public static void test2() { 103 BPlusTree<Integer, Integer> myTree = new BPlusTree<Integer, Integer>(10, InputDataOrder.RANDOM); 104 105 int max = 10_000_000; 106 int min = -max; 107 int numCount = max - min + 1; 108 int numRealCount = 0; 109 110 Integer[] data = new Integer[max - min + 1]; 111 for (int i = 0; i < data.length; i++) { 112 data[i] = 0; 113 } 114 115 // 产生数据 116 long start = System.currentTimeMillis(); 117 int key; 118 for (int i = 0; i < numCount; i++) { 119 key = getRandom(min, max, true); 120 // key = i + min; 121 // try { 122 // Thread.sleep(1000); 123 // } catch (InterruptedException e) { 124 // // TODO Auto-generated catch block 125 // e.printStackTrace(); 126 // } 127 myTree.set(key, key); 128 if (data[key - min] == 0) { 129 numRealCount++; 130 data[key - min] = 1; 131 } 132 } 133 System.out.println( 134 numRealCount + " data from " + numCount + "[" + min + "," + max + "] has been inserted into tree"); 135 System.out.println("time cost for insert: " + (System.currentTimeMillis() - start)); 136 System.out.println("tree leaf entry: " + myTree.getDataCount() + ", hashmap count:" + numRealCount); 137 138 // 查数据 139 System.out.println(); 140 System.out.println("getDataCount:" + myTree.getDataCount()); 141 System.out.println("height:" + myTree.getHeight()); 142 start = System.currentTimeMillis(); 143 int getCount = 0; 144 for (int i = 0; i < data.length; i++) { 145 if (data[i] == 1) { 146 getCount++; 147 key = i + min; 148 if (!myTree.get(key).equals(key)) { 149 System.err.println("error for get: " + myTree.get(key) + " " + key); 150 System.exit(1); 151 } 152 } 153 } 154 System.out.println("time cost for " + getCount + " get: " + (System.currentTimeMillis() - start)); 155 156 // 删除数据 157 System.out.println(); 158 start = System.currentTimeMillis(); 159 System.out.println(myTree.getDataCount()); 160 for (int i = data.length; i >= 0; i--) { 161 try { 162 myTree.remove(i + min); 163 } catch (Exception e) { 164 // TODO: handle exception 165 System.err.println(String.format("remove error: i=%d, key=%d \n", i, i + min)); 166 e.printStackTrace(); 167 System.exit(0); 168 } 169 } 170 System.out.println("getDataCount:" + myTree.getDataCount()); 171 System.out.println("height:" + myTree.getHeight()); 172 myTree.printTree(); 173 myTree.remove(-2); 174 System.out.println("time cost for remove: " + (System.currentTimeMillis() - start)); 175 } 176 177 public static void test1() { 178 BPlusTree<Integer, Integer> myTree = new BPlusTree<Integer, Integer>(8, InputDataOrder.RANDOM); 179 180 int max = 200 * 25000; 181 long start = System.currentTimeMillis(); 182 for (int i = 0; i < max; i++) { 183 myTree.set(i, i); 184 } 185 System.out.println(max + " Data has been inserted into tree"); 186 System.out.println("time cost for BPlusTree: " + (System.currentTimeMillis() - start)); 187 188 System.out.println(); 189 System.out.println("height: " + myTree.getHeight()); 190 System.out.println(myTree.get(2345)); 191 System.out.println(); 192 193 start = System.currentTimeMillis(); 194 for (int i = 0; i < max; i++) { 195 myTree.get(i); 196 } 197 System.out.println("time cost for get: " + (System.currentTimeMillis() - start)); 198 199 start = System.currentTimeMillis(); 200 Map<Integer, String> hashMap = new HashMap<Integer, String>(); 201 for (int i = 0; i < max; i++) { 202 hashMap.put(i, i + ""); 203 } 204 System.out.println("time cost for HashMap: " + (System.currentTimeMillis() - start)); 205 206 for (int i = 0; i < max; i++) { 207 if (myTree.get(i) != i) { 208 System.err.println("error for: " + i); 209 } 210 } 211 212 System.out.println("Success"); 213 214 // myTree.remove(2); 215 // myTree.printTree(myTree.getRoot()); 216 } 217 218 public static void test3() { 219 BPlusTree<Integer, String> myTree = new BPlusTree<Integer, String>(3, InputDataOrder.RANDOM); 220 221 int max = 7; 222 for (int i = 0; i < max; i++) { 223 // System.out.println("__insert " + i); 224 myTree.set(i, i + ""); 225 // myTree.printTree(myTree.getRoot()); 226 // System.out.println(); 227 228 // System.out.println("__insert " + (2 * max - i)); 229 myTree.set(2 * max - i, 2 * max - i + ""); 230 // myTree.printTree(myTree.getRoot()); 231 // System.out.println(); 232 } 233 234 System.out.println("tree height:" + myTree.getHeight()); 235 System.out.println("leaf entry count:" + myTree.getDataCount()); 236 System.out.println(); 237 238 myTree.printTree(); 239 System.out.println(); 240 241 for (int i = 0; i < max; i++) { 242 System.out.println("__remove " + i); 243 myTree.remove(i); 244 myTree.printTree(); 245 246 System.out.println("__remove " + (2 * max - i)); 247 myTree.remove(2 * max - i); 248 myTree.printTree(); 249 System.out.println(); 250 } 251 252 } 253 254 }
一、二叉树与树、森林的转换
二叉树与通常树的双向转换、与森林的双向转换。(通常树转为二叉树后根节点度为1,包含多棵树的森林转为二叉树后根节点度为2)。二叉树转为树或森林时,该二叉树须是由后者转换而来的。
二、树、森林的遍历:
a、二叉树:前序、中序、后序、层次
b、树:前序、后序
c、森林:前序(即按树的前序遍历依次遍历每棵树)、中序(即按树的后序遍历方式依次遍历每棵树,尼玛叫后序更合适吧)
将树或森林转为二叉树或反向转换后:(不用记,举个例子就明了了)
二叉树的前序、树的前序、森林的前序遍历序列同样
二叉树的中序、树的后序、森林的中序(尼玛你若叫后序遍历这里就统一了)同样