【专题】二叉树

这两天的任务是二叉树_(:з」∠)_

首先是理论学习部分。

子树满二叉树完全二叉树这类基础概念就不介绍了,这里只记一些我觉得老记不住的:

1.平衡二叉树——平衡二叉树又被称为AVL树(区别于AVL算法),它是一棵二叉排序树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

主要的性质:

二叉树性质

(1) 在非空二叉树中,第i层的结点总数不超过 , i>=1;

(2) 深度为h的二叉树最多有  个结点(h>=1),最少有h个结点;

(3) 对于任意一棵二叉树,如果其叶结点数为N_0,而度数为2的结点总数为N_2,则N_0=N_2+1;
(4) 具有n个结点的完全二叉树的深度为
(5)有N个结点的完全二叉树各结点如果用顺序方式存储,则结点之间有如下关系:
若I为结点编号则 如果I>1,则其父结点的编号为I/2;
如果2*I<=N,则其左儿子(即左子树的根结点)的编号为2*I;若2*I>N,则无左儿子;
如果2*I+1<=N,则其右儿子的结点编号为2*I+1;若2*I+1>N,则无右儿子。
(6)给定N个节点,能构成h(N)种不同的二叉树。
h(N)为卡特兰数的第N项。h(n)=C(2*n,n)/(n+1)。
(7)设有i个枝点,I为所有枝点的道路长度总和,J为叶的道路长度总和J=I+2*i
 
二叉树光是看理论的话其实没什么用。所以接下来上例题

 1.FBI树

题目描述

我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全“1”串称为I串,既含“0”又含“1”的串则称为F串。

FBI树是一种二叉树,它的结点类型也包括F结点,B结点和I结点三种。由一个长度为2^N的“01”串S可以构造出一棵FBI树T,递归的构造方法如下:

1) T的根结点为R,其类型与串S的类型相同;

2) 若串S的长度大于1,将串S从中间分开,分为等长的左右子串S1和S2;由左子串S1构造R的左子树T1,由右子串S2构造R的右子树T2。

现在给定一个长度为2^N的“01”串,请用上述构造方法构造出一棵FBI树,并输出它的后序遍历序列。

输入输出格式

输入格式:

 

第一行是一个整数N(0 <= N <= 10),第二行是一个长度为2^N的“01”串。

 

输出格式:

 

包括一行,这一行只包含一个字符串,即FBI树的后序遍历序列。

 

输入输出样例

输入样例#1: 
3
10001011
输出样例#1: 
IBFBBBFIBFIIIFF

说明

对于40%的数据,N <= 2;

对于全部的数据,N <= 10。

 这应该是比较经典的一道二叉树题了吧。比较简单,但这里主要想说一个技巧。
这道题主要是考察求后序遍历。我们知道,后序遍历是左右根,但用递归其实是不好实现的。原因如下:一般来说,递归都是从最上面的根开始,有了父亲接下来才会搜到儿子,那么就不可能显得出两个儿子再反推出父亲。解决方法其实也很简单,就是完全反过来储存。也就是说,后序遍历是左右根,那么我们在查找的时候就按根右左的顺序储存,这样最后从后往前输出就行了。
感觉这个技巧在二叉树里还挺有用的,见到好几次了。(至少在求x序遍历上是用得到的)
另外,这道题在做的时候虽然思路很顺,但是递归退出的条件调了好久都没调对。
 1 #include <iostream>
 2 #include <cmath>
 3 #include <cstring>
 4 #include <cstdio>
 5 #include <cstdlib>
 6 #include <algorithm>
 7 using namespace std;
 8 string s,ans;
 9 bool ok=true;
10 void build(int l,int r)
11 {
12     if(!ok) ok=true;  //这里不能再return了,不然最后一层的左儿子就无法输出了 
13     if(l>r) return ;
14     bool B=true,I=true;
15     for(int i=l;i<=r;i++)
16     {
17         if(s[i]=='0') I=false;
18         if(s[i]=='1') B=false;
19         if(!B && !I) break;
20     }
21     if(!B && !I) ans+='F';
22     else if(B) ans+='B';
23     else ans+='I';
24     if(l==r) {ok=false;return ;}  
25     /*如果当前是叶子结点,就不能再一分为二了。此时应返回上一层(其父亲):若当前为右儿子,则接下来搜左儿子;若当前是左儿子,则接下来再后退搜另一个节点 */
26     build((l+r)/2+1,r);  //先右 
27     build(l,(l+r)/2);   //后左 
28 }
29 int main()
30 {
31     int n;
32     scanf("%d",&n);
33     cin>>s;
34     build(0,s.size()-1);  //对于string类型:size()可用来求长度。但要注意直接cin的话是从0开始的 
35     for(int i=ans.size()-1;i>=0;i--) cout<<ans[i];
36     return 0;
37 }
P1087

 

posted @ 2018-01-31 14:48  小蒟蒻  阅读(111)  评论(0编辑  收藏  举报