一、题目:
在度为4的树中,若有20个度为4的节点,10个度为3的节点,1个度为2的节点,10个度为1的节点,则树T的叶节点个数是?
这道题是2010年计算机联考真题。我用手算(半蛮力)解出答案是82,结果是对的,但是耗时较长,而且如果数字再大点也不好算了,因此肯定存在一种更加高效的方法。
我们知道,
- 树的节点的个数=树的度+1
于是树的节点个数N = 1 + 20*4 + 10*3 + 1*2 + 10*1
但同时,树的节点个数也可以写成是:叶子节点数+度为1的节点数+…+度为4的节点数
即N = N0 + 20 + 10 + 1 + 10
,其中N0为叶子节点个数
由上述两个式子就可解出叶子节点个数为82了。
这个方法解题效率比半蛮力法高多了,而且更准确
二、题目
设二叉树有2n个节点,且
m<n
,不可能存在()的节点
A. n个度为0 B. 2m个度为0 C. 2m个度为1 D. 2m个度为2
这道题涉及到的知识为:
- 二叉树中,叶节点的数目N0等于度为2的节点数目N2加一。 即
N0 = N2 + 1
设度为i
的节点的数量为Ni
,则 2n = N0 + N1 + N2
又因N0 = N2 + 1
,故2n = N1 + 2N2 + 1
因此可以推算出 N1 = 2n - 2N2 -1
,必为奇数,由此直接判断本题选C
三、题目
【2009年计算机联考真题】若一颗完全二叉树有768个结点,则该二叉树叶节点个数为?
该题有两种算法。
算法一:
- 完全二叉树中最后一个树枝节点的编号为
n/2
因此该完全二叉树最后一个数值结点的编号为768/2=384
(从1开始编号),所以叶子节点个数为768-384=384
算法二:
设N
为二叉树总节点数,Ni
为 度为i
的节点数N = N0 + N1 + N2
, N0 = N2 + 1
,即 N = N1 + 2N2 + 1
因此768 = N1 + 2N2+1,而N1只能等于0或1(完全二叉树中)
所以可以解出N1 = 1,N2 = 383,所以N0 = N2+1=384
四、题目
已知一棵有2011个结点的树,其叶结点个数是11个,该树对应的二叉树中无右孩子的结点的个数是?
该题可参考该博客:链接跳转
需要注意的是树转换为二叉树时,是左孩子右兄弟,上述博客中有笔误。
五、题目
在二叉树中有两个结点m和n,如果m是n的祖先,可以找到从m到n的路径的遍历方式是?
这道题想了我很久,答案是 后序遍历
似乎有点难以理解,试想先序遍历、中序遍历、层次遍历都会遍历到m和n啊,层次遍历和路径无关,自然不选,但是先序和中序为何不行?
这就得先看清楚,题目中所写为 m是n的祖先,祖先可不仅仅只能是父节点。如果是父节点,那么不管哪一种都好说。而祖先的话,试想 n是m的第18代儿子,假设又是满二叉树,天呐,从记录下m开始到找到n,中间可能性有多少?2的18次方种可能,显然全部记录下来然后从中选一个是不现实的吧,所以从上往下找,这种思路本就是不可行的。(没说清楚?和这个问题很像,可以参考:戳)打个更简单的比方,一个皇帝想从几十亿的人中找到你是很难的,但是你想找那个皇帝,却是很简单的。
而既然排除了从上往下,也就排除了先序和中序,那后序为什么可以呢?因为后序遍历,无论是在左子树还是右子树,在返回的路上,都必然会经过祖先节点,所以,不管是不是递归的方法,都可以找得到这条路径。
非递归求解该问题的伪代码见第八题,只要从栈中提出n,则栈里面剩下的就是从根节点到n的路径节点。
六、题目
线索二叉树是一种( )结构?
A. 逻辑
B. 逻辑和存储
C. 物理
D. 线性
答案选C,解题方案见:该题题解
七、题目
()的遍历仍需要栈的支持
A. 前序线索树
B. 中序线索树
C. 后序线索树
D. 所有线索树
这是一道很简单的题目,显然选C,因为后序线索树可能不能根据线索找到直接后继节点。
这里小结一下:
- 先序线索二叉树可以求先序后继
- 先序线索二叉树不可以求先序前驱
- 中序线索二叉树可以求中序后继
- 中序线索二叉树可以求中序前驱
- 后序线索二叉树不可以求后序后继
- 后序线索二叉树可以求后序前驱
八、编程题
编写后序遍历二叉树的非递归算法
后序遍历二叉树,如果使用递归很简单,就三五句话
void PostOrder(BiTree T)
{
if(T != NULL)
{
PostOrder(T->lchild);
PostOrder(T->Rchild);
visit(T);
}
}
但是使用非递归算法,后序遍历是最麻烦的一种了,代码如下:
void PostOrder(BiTree T)
{
InitStack(S);
BiTree *p = T;
//r指针用来指向上一个访问过的节点
//用于在访问一棵子树的根节点时判断是从左子树返回还是右子树返回
BiTree *r = T;
while(p && !IsEmpty(S))
{
if(p)
{
//找到最左端的节点,路径上的节点全部入栈,包括叶子节点
push(S,p);
p = p->lchild;
}
else
{
GetTop(S,p);
if(p->rchild && p->rchild!=r)
{
//如果p有右孩子,且右孩子未被访问过
p = p->rchild;
push(S,p);
p = p->lchild; //再走到最左
}
else
{
pop(S,p);
visit(p);
r = p;
p = NULL;
}
}
}
}
请画图理解上述代码。且上述代码适用于其他情况。
当访问一个节点*p
时,栈里节点恰好是*p
节点的所有祖先。这构成了从根节点到*p
节点的一条路径,因此本算法可以求最短路径、两个节点的最近公共祖先等。
九、题目
含有二十个节点的平衡二叉树的最大深度为()
A. 4 B. 5 C. 6 D. 7
这道题涉及到的就是平衡二叉树里的一个规律:
- 假设以Nh表示深度为h的平衡树中含有的最少节点数,那么
N0 = 0 ,N1 = 1, N2 = 2
,并且有Nh = Nh-1 + Nh-2 + 1
所以这道题很明显了,N0 = 0, N1 = 1, N2 = 2, N3 = 4, N4 = 7, N5 = 12, N6 = 20
所以选 C
十、综合应用题
画出一个二叉树,使它既满足大根堆的要求又满足二叉排序树的要求
这道题看似是一道开放性的题,所以看着觉得很奇怪。然而这是因为我不知道大根堆是什么东西的原因。
所谓大根堆,下面是百度百科的解释:
最大堆是堆的两种形式之一。
根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最大者,称为大根堆,又称最大堆(大顶堆)。
大根堆要求根节点的关键字既大于或等于左子树的关键字值,又大于或等于右子树的关键字值。
而且,大根堆还要求树是完全二叉树。
数据结构老师没教过堆排序的弱渣飘过
然后就很简单了,首先,根节点比左右节点都大,而且二叉排序树要求根节点比右节点小,那么没有右节点就得了。然后因为又要求必须是完全二叉树,所以这棵树只能有两个节点,一个根节点,一个是根节点的左节点。所以这棵树是唯一的!!!
本以为是唯一的,但是经道友指点,还可以是只有一个根节点的情况,那么就是这两种情况啦!