1~5 A D D C A
6~10 C C B D C
11~15 B C A C A
(1)把一棵树转换为二叉树后,这棵二叉树的形态是(A) 。
A.唯一的B.有多种
C.有多种,但根结点都没有左孩子D.有多种,但根结点都没有右孩子
因为二叉树有左孩子、右孩子之分,故一棵树转换为二叉树后,这棵二叉树的形态是唯一的。
(2)由3 个结点可以构造出多少种不同的二叉树?(D)
A. 2 B . 3 C . 4 D .5
(3)一棵完全二叉树上有1001 个结点,其中叶子结点的个数是(D) 。
A. 250 B . 500 C . 254 D . 501
设度为0 结点(叶子结点)个数为n0,度为1 的结点个数为n1,度为2 的结点个数为n2,有n0=n2+1,n0+n1+n2=1001
由完全二叉树的性质可得n1=0 或1,即有501 个叶子结点。
(4)一个具有1025 个结点的二叉树的高h 为(C) 。
A. 11. 10 C . 11 至1025 之间D. 10 至1024 之间
若每层仅有一个结点,则树高h 为1025 ;且其最小树高为log 2 1025 + 1=11 ,即h 在11 至1025 之间。
(5)深度为h 的满m叉树的第k 层有(A)个结点。(1=
A. mk-1 B. mk-1 C . mh-1 D . mh-1
深度为h 的满m叉树共有mh-1 个结点,第k 层有mk-1 个结点。
(6)利用二叉链表存储树,则根结点的右指针是(C) 。
A.指向最左孩子 B .指向最右孩子 C .空 D .非空
利用二叉链表存储树时,规则为:兄弟相连、长兄为父、孩子靠左、兄弟靠右,右指针是指向兄弟结点,因为根节点没有兄弟结点,故根节点的右指针指向空。
(7)对二叉树的结点从1 开始进行连续编号,要求每个结点的编号大于其左、右孩子的编号,同一结点的左右孩子中,其左孩子的编号小于其右孩子的编号,可采用(C)遍历实现编号。
A.先序 B. 中序 C. 后序 D. 从根开始按层次遍历
根据题意可知按照先左孩子、再右孩子、最后双亲结点的顺序遍历二叉树,即后序遍历二叉树。
(8) 在一棵度为4 的树T 中, 若有20 个度为4 的结点, 10 个度为3 的结点, 1 个度为2 的结点, 10个度为1 的结点, 则树T 的叶结点个数是(B)。
A. 41 B. 82
C. 113 D. 122
度为4,不是二叉树!!!
先求总节点个数为:根节点+子节点
根节点个数为1 + 子节点个数为204+103+12+101 = 123
非叶子结点总数为20+10+1+10 =41个
故叶结点=123-41=82个
(9)在下列存储形式中, (D)不是树的存储形式?
A.双亲表示法 B .孩子链表表示法C.孩子兄弟表示法D.顺序存储表示法
树的存储结构有三种:双亲表示法、孩子表示法、孩子兄弟表示法
(10)一棵非空的二叉树的先序遍历序列与后序遍历序列正好相反,则该二叉树一定满足(C) 。
A.所有的结点均无左孩子 B .所有的结点均无右孩子
C.只有一个叶子结点 D .是任意一棵二叉树
因为先序遍历结果是“中左右” ,后序遍历结果是“左右中” ,当没有左子树时,就是“中右”和“右中” ;当没有右子树时,就是“中左”和“左中” 。则所有的结点均无左孩子或所有的结点均无右孩子均可,所以A、B 不能选,又所有的结点均无左孩子与所有的结点均无右孩子时,均只有一个叶子结点,故选C。
(11)设哈夫曼树中有199 个结点,则该哈夫曼树中有(B)个叶子结点。
A. 99 B. 100
C. 101 D. 102
在哈夫曼树中只有度为0(叶子结点)和度为2 的结点。设叶子结点的个数为n0,度为2 的结点的个数为n2,由二叉树的性质n0=n2+1 ,则总结点数n=n0+n2=2*n0-1 ,得到n0=100 。
(12)若X 是二叉中序线索树中一个有左孩子的结点,且X 不为根,则X 的前驱为(C) 。
A. X 的双亲B. X 的右子树中最左的结点
C. X 的左子树中最右结点 D . X 的左子树中最右叶结点
按照中序遍历的顺序,X的上一个刚刚访问过的结点就应为X左子树最右的结点
(13)引入二叉线索树的目的是(A) 。
A.加快查找结点的前驱或后继的速度 B .为了能在二叉树中方便的进行插入与删除
C.为了能方便的找到双亲 D .使二叉树的遍历结果唯一
以二叉链表作为存储结构时,只能得到节点的左右孩子信息,结点的任意序列中的前驱和后继信息只能在遍历的动态过程中才能得到,为了查找结点的前驱或后继,引入线索二叉树。
(14)设F 是一个森林, B 是由F 变换得的二叉树。若F 中有n 个非终端结点,则B 中右指针域为空的结点有(C)个。
A. n- 1 B. n C. n + 1 D. n + 2
森林转换为二叉树,"兄弟相连、长兄为父、孩子靠左、头根为根 ",F有n个非终端节点,所以转换为二叉树后所有的空的右指针域就是n个根节点没有兄弟,根结点的右指针域也为空,二叉树中右指针域为空的节点有(n+1)个.
(15)n( n≥2)个权值均不相同的字符构成哈夫曼树, 关于该树的叙述中, 错误的是(A)。
A.该树一定是一棵完全二叉树
B.树中一定没有度为1 的结点
C.树中两个权值最小的结点一定是兄弟结点
D.树中任一非叶结点的权值一定不小于下一层任一结点的权值
哈夫曼树的构造过程是每次都选取权值最小的树作为左右子树构造一棵新的二叉树,所以树中一定没有度为1 的结点、两个权值最小的结点一定是兄弟结点、任一非叶结点的权值一定不小于下一层任一结点的权值。
(1)试找出满足下列条件的二叉树
① 先序序列与后序序列相同②中序序列与后序序列相同
③ 先序序列与中序序列相同④中序序列与层次遍历序列相同
先序遍历:“根—左子树—右子树” ,中序遍历:“左子树—根—右子树” ,后序遍历: “左子树—右子树―根",根据以上原则有:
1)若先序序列与后序序列相同,则或为空树,或为只有根结点的二叉树.
2)若中序序列与后序序列相同,则或为空树,或为任一结点至多只有左子树的二叉树.
3)若先序序列与中序序列相同,则或为空树,或为任一结点至多只有右子树的二叉树.
4)若中序序列与层次遍历序列相同,则或为空树,或为任一结点至多只有右子树的二叉树
(2)设一棵二叉树的先序序列: A B D F C E G H ,中序序列: B F D A G E H C
①画出这棵二叉树。
②画出这棵二叉树的后序线索树。
③将这棵二叉树转换成对应的树(或森林) 。
解析:1)先找出根结点,先序遍历规则为DLR,所以A为根节点;根据中序遍历LDR将二叉树分为 BFD 和GEHC;再根据先序遍历,可知B、C为A的左右子树,同理可画出这棵二叉树
2)后序遍历为LRD,所以后序遍历为 F D B G H E C A
(3)假设用于通信的电文仅由8 个字母组成, 字母在电文中出现的频率分别为0.07 ,0.19 ,0.02 , 0.06 , 0.32 , 0.03 , 0.21 , 0.10 。
①试为这8 个字母设计哈夫曼编码。
② 试设计另一种由二进制表示的等长编码方案。
③对于上述实例,比较两种方案的优缺点。
方案1;哈夫曼编码
1、码字不同
哈夫曼所构造的码字不是唯一的,对于同一个信息源,无论上述的前后顺序如何排列,它的平均码长是不会改变的,所以他的优点是编码效率唯一性。而二进制编码所构造的码字是唯一。
2、长度不同
哈夫曼编码是依据字符出现概率来构造异字头的平均长度最短的码字,比较精准,二进制编码是用预先规定的方法将文字、数字或其他对象编成二进制的数码,或将信息、数据转换成规定的二进制电脉冲信号。二进制是最基础的编码。
3、稳定性不同
哈夫曼编码的稳定性比较差。如果改变其中一位数据就会产生改变。二进制编码具有抗干扰能力强,可靠性高等优点。
(4)已知下列字符A、B、C、D、E、F、G的权值分别为3、12 、7、4、2、8, 11,试填写出其对应哈夫曼树HT 的存储结构的初态和终态。
以二叉链表作为二叉树的存储结构,编写以下算法:
(1)统计二叉树的叶结点个数。
[ 题目分析]
如果二叉树为空,返回0,如果二叉树不为空且左右子树为空,返回1,如果二叉树不为空,且左右子树不同时为空,返回左子树中叶子节点个数加上右子树中叶子节点个数。
[ 算法描述]
int LeafNodeCount(BiTree T){
// 如果是空树,则叶子结点个数为0
if(T==NULL)
return 0;
// 判断结点是否是叶子结点(左孩子右孩子都为空) ,若是则返回1
else if(T->lchild==NULL&&T->rchild==NULL)
return 1;
else
return LeafNodeCount(T->lchild)+LeafNodeCount(T->rchild);
}
(2)判别两棵树是否相等。
[ 题目分析]
先判断当前节点是否相等( 需要处理为空、是否都为空、是否相等) ,如果当前节点不相等, 直接返回两棵树不相等; 如果当前节点相等, 那么就递归的判断他们的左右孩子是否相等。
[ 算法描述]
int compareTree(TreeNode* tree1, TreeNode* tree2){
// 用分治的方法做,比较当前根,然后比较左子树和右子树
bool tree1IsNull = (tree1==NULL);
bool tree2IsNull = (tree2==NULL);
if(tree1IsNull != tree2IsNull) return 1;
if(tree1IsNull && tree2IsNull) return 0;
if(tree1->c != tree2->c) return 1;
return (compareTree(tree1->left,tree2->left)&compareTree(tree1->right,tree2->right))
(compareTree(tree1->left,tree2->right)&compareTree(tree1->right,tree2->left));
}
3)交换二叉树每个结点的左孩子和右孩子。
[ 题目分析]
如果某结点左右子树为空,返回,否则交换该结点左右孩子,然后递归交换左右子树。
[ 算法描述]
void ChangeLR(BiTree &T){
BiTree temp;
if(T->lchild==NULL&&T->rchild==NULL) return;
else{
temp = T->lchild;
T->lchild = T->rchild;
T->rchild = temp;
}
ChangeLR(T->lchild); // 递归交换左子树
ChangeLR(T->rchild); //递归交换右子树
}
(4)设计二叉树的双序遍历算法(双序遍历是指对于二叉树的每一个结点来说,先访问这个结点,再按双序遍历它的左子树,然后再一次访问这个结点,接下来按双序遍历它的右子树) 。
[ 题目分析]
若树为空,返回;若某结点为叶子结点,则仅输出该结点;否则先输出该结点,递归遍历其左子树,再输出该结点,递归遍历其右子树。
[ 算法描述]
void DoubleTraverse(BiTree T){
if(T == NULL) return;
else if(T->lchild==NULL&&T->rchild==NULL)
cout<<T->data; // 叶子结点输出
else{
cout<<T->data;
DoubleTraverse(T->lchild); // 递归遍历左子树
cout<<T->data;
DoubleTraverse(T->rchild); // 递归遍历右子树
}
}
(5)计算二叉树最大的宽度(二叉树的最大宽度是指二叉树所有层中结点个数的最大值) 。
[ 题目分析]
求二叉树高度的算法见上题。求最大宽度可采用层次遍历的方法, 记下各层结点数,每层遍历完毕,若结点数大于原先最大宽度,则修改最大宽度。
[ 算法描述]
int Width(BiTree bt){
if (bt==null) return (0); // 空二叉树宽度为0
else{
BiTree Q[];
front=1;rear=1;last=1;
temp=0; maxw=0;
Q[rear]=bt; // 根结点入队列
while(front<=last){
p=Q[front++]; temp++; // 同层元素数加1
if (p->lchild!=null) Q[++rear]=p->lchild;
if (p->rchild!=null) Q[++rear]=p->rchild;
if (front>last) {
last=rear;
if(temp>maxw) maxw=temp;
//last 指向下层最右元素, 更新当前最大宽度
temp=0;
}
}
return (maxw);
}
}
(6)用按层次顺序遍历二叉树的方法,统计树中具有度为1 的结点数目。
[ 题目分析]
若某个结点左子树空右子树非空或者右子树空左子树非空,则该结点为度为1的结点
[ 算法描述]
int Level(BiTree bt) {
int num=0;
if(bt){
QueueInit(Q); QueueIn(Q,bt);
while(!QueueEmpty(Q)){
p=QueueOut(Q); cout<<p->data;
if(p->lchild && !p->rchild ||!p->lchild && p->rchild) num++;
if(p->lchild) QueueIn(Q,p->lchild);
if(p->rchild) QueueIn(Q,p->rchild);
}
}
return(num);
}
(7)求任意二叉树中第一条最长的路径长度,并输出此路径上各结点的值。
[ 题目分析]
因为后序遍历栈中保留当前结点的祖先的信息,用一变量保存栈的最高栈顶指针,每当退栈时,栈顶指针高于保存最高栈顶指针的值时,则将该栈倒入辅助栈中,辅助栈始终保存最长路径长度上的结点,直至后序遍历完毕,则辅助栈中内容即为所求。
[ 算法描述]
int Depth(BiTree T)/* 深度 */
{
if(T==NULL)
return(0);
return 1+(Depth(T->lchild)>Depth(T->rchild)? Depth(T->lchild):Depth(T->rchild));
//选择左右孩子深度高的然后加上根节点这一层就是深度
}
void Long(BiTree T)
{
if(T!=NULL)//在T不为空的情况下
{
visit(T->data);//访问节点
if(Depth(T->lchild)>Depth(T->rchild))//判断往左走还是往右走
Long(T->lchild);
else
Long(T->rchild);
}
}
(8)输出二叉树中从每个叶子结点到根结点的路径。
[ 题目分析]
采用先序遍历的递归方法, 当找到叶子结点b 时, 由于b 叶子结点尚未添加到path 中,因此在输出路径时还需输出b->data 值。
[ 算法描述]
void AllPath(BTNode *b,ElemType path[],int pathlen){
int i;
if (b!=NULL){
if (b->lchild==NULL && b->rchild==NULL) { //*b 为叶子结点
cout << " " << b->data << " 到根结点路径:" << b->data;
for (i=pathlen-1;i>=0;i--)
cout << endl;
}else{
path[pathlen]=b->data; // 将当前结点放入路径中
pathlen++; //路径长度增1
AllPath(b->lchild,path,pathlen); // 递归扫描左子树
AllPath(b->rchild,path,pathlen); // 递归扫描右子树
pathlen--;
}
}
}