1. 背景
今天复习数据结构的时候遇到一个题目,内容如下:
【2015统考真题】先序序列为a,b,c,d的不同二叉树的个数为()
A. 13 B.14 C.15 D.16
王道答案如下:
个人感觉有点难理解,为什么可以把原题目等价为"以序列a,b,c,d为入栈次序,则出栈序列的个数为?",这其中的联系在哪?在查阅了许多资料后,我决定从另一个方向来重新分析这个问题。
2. 题目分析
“已知先序序列的结果,求满足的二叉树的个数?”,首先让我们来想一想,题目给的先序序列的结果在这里起到了什么限制作用吗?答案是:没有。原题目等价于“已知一个二叉树有n个节点,求不同的二叉树的个数”,题目所给的先序序列仅仅告诉我们,二叉树的节点个数为4。
这听起来似乎有点违背直觉,难道先序遍历的结果没有任何作用吗?不要着急,请听我慢慢解释。
以3个节点的二叉树为例
3个节点构成的不同的二叉树共有5种,分别为:
先序序列为a,b,c的二叉树有5种,分别为:
先序遍历a,c,b的二叉树也是5种,分别为:
通过观察可以发现,三者的结果个数是一样的!也就是说,对于给定的遍历结果,只是把字母对应的填进了n个节点构成的所有的二叉树中而已,遍历的结果是什么并不会影响二叉树的数量。
由此我们还可以得出推论:
- 给定二叉树先序遍历结果,求满足结果的不同的树的个数
- 给定二叉树中序遍历结果,求满足结果的不同的树的个数
- 给定二叉树后序遍历结果,求满足结果的不同的树的个数
- 给定二叉树层序遍历结果,求满足结果的不同的树的个数
以上问题全部与 “n个节点能够构成的不同的二叉树的个数?” 等价
但是我们要如何求出n个节点能够构成的二叉树的数量呢?这似乎也是一个难以解决的问题。想要解决这个问题就需要介绍一下大名鼎鼎的"卡特兰数"了。
3. 问题求解
3.1 卡特兰数
卡特兰数是组合数学中一个常出现于各种计数问题中的数列。以中国蒙古族数学家明安图和比利时数学家欧仁·查理·卡特兰的名字命名,其前几项为(从第0项开始):1, 1, 2, 5, 14, 42…
关于卡特兰数的具体内容不做过多介绍,感兴趣的读者可以自行查阅,我们主要来看卡特兰数的形式:
设
h
(
n
)
h(n)
h(n)为卡特兰数的第
n
n
n项,其中
h
(
0
)
=
1
,
h
(
1
)
=
1
h(0)=1,h(1)=1
h(0)=1,h(1)=1,则卡特兰数满足递推式
(
n
≥
2
)
(n \geq 2)
(n≥2):
h
(
n
)
=
∑
i
=
0
n
−
1
h
(
i
)
∗
h
(
n
−
1
−
i
)
=
h
(
0
)
∗
h
(
n
−
1
)
+
h
(
1
)
∗
h
(
n
−
2
)
+
⋯
+
h
(
n
−
1
)
∗
h
(
0
)
h(n) = \sum_{i=0}^{n-1}h(i)*h(n-1-i)=h(0)*h(n-1)+h(1)*h(n-2)+\cdots+h(n-1)*h(0)
h(n)=i=0∑n−1h(i)∗h(n−1−i)=h(0)∗h(n−1)+h(1)∗h(n−2)+⋯+h(n−1)∗h(0)
递推关系的解为:
h
(
n
)
=
1
n
+
1
C
2
n
n
h(n) = \frac{1}{n+1}C_{2n}^n
h(n)=n+11C2nn
接下来,我们借助卡特兰数的公式来推出n个节点能够构成的不同的二叉树的个数。
3.2 推导过程
3.2.1 三个节点的情况
设 h ( n ) h(n) h(n)为 n n n个节点能够构成的不同的二叉树的个数,这里认为空树也算作一种,即 h ( 0 ) = 1 h(0)=1 h(0)=1,同时不难得出 h ( 1 ) = 1 , h ( 2 ) = 2 h(1)=1,h(2)=2 h(1)=1,h(2)=2
接下来我们以
n
=
3
n=3
n=3为例进行推导:
如图,3个节点中使用1个作为根结点,对于剩余的2个节点可以进行如下的分配方法:
- 2个节点构成根节点的左子树,0个节点构成根节点的右子树,共有 h ( 2 ) ∗ h ( 0 ) h(2)*h(0) h(2)∗h(0)种结果
- 1个节点构成根节点的左子树,1个节点构成根节点的右子树,共有 h ( 1 ) ∗ h ( 1 ) h(1)*h(1) h(1)∗h(1)种结果
- 0个节点构成根节点的左子树,2个节点构成根节点的右子树,共有 h ( 0 ) ∗ h ( 2 ) h(0)*h(2) h(0)∗h(2)种结果
综上所述:3个节点构成的不同的二叉树的个数为: h ( 3 ) = h ( 2 ) ∗ h ( 0 ) + h ( 1 ) ∗ h ( 1 ) + h ( 0 ) ∗ h ( 2 ) = 5 h(3)=h(2)*h(0)+h(1)*h(1)+h(0)*h(2)=5 h(3)=h(2)∗h(0)+h(1)∗h(1)+h(0)∗h(2)=5
3.2.2 n个节点的情况
将上述结论推广到
n
n
n个节点:
同理,1个节点作为根节点,剩余
n
−
1
n-1
n−1个节点可以按上述分配方法进行分配,可以得到:
h
(
n
)
=
h
(
n
−
1
)
∗
h
(
0
)
+
h
(
n
−
2
)
∗
h
(
1
)
+
⋯
+
h
(
1
)
∗
h
(
n
−
2
)
+
h
(
0
)
∗
h
(
n
−
1
)
h(n)=h(n-1)*h(0)+h(n-2)*h(1)+\cdots+h(1)*h(n-2)+h(0)*h(n-1)
h(n)=h(n−1)∗h(0)+h(n−2)∗h(1)+⋯+h(1)∗h(n−2)+h(0)∗h(n−1)
正好满足卡特兰数的递推式,即:
h
(
n
)
=
1
n
+
1
C
2
n
n
h(n)=\frac{1}{n+1}C_{2n}^n
h(n)=n+11C2nn
4.总结
对于一个给定的遍历结果(不论是先序遍历、中序遍历、后序遍历还是层序遍历),其对应的不同的二叉树的个数等于n个节点构成的不同的二叉树的个数,即为卡特兰数。
卡特兰数可以由下述公式进行计算:
h
(
n
)
=
1
n
+
1
C
2
n
n
h(n)=\frac{1}{n+1}C_{2n}^n
h(n)=n+11C2nn