试题1(王道5.3.3节第16题):
设计算法将二叉树的叶结点按从左到右的顺序连成单链表,连接时使用叶结点的右指针域存放单链表指针。
借助遍历算法完成:
//根据二叉树层次遍历序列构造单链表
void LevelOrdertoLinkList(BiTree &T){
Queue q;
InitQueue(q);
BiTree p = T;
BiTree pre = NULL;
InsertQueue(q, p);
while(!IsQueueEmpty(q)){
p = DeleteQueue(q, p);
if(p->lchild!=NULL)
InsertQueue(q, p->lchild);
if(p->rchild!=NULL)
InsertQueue(q, p->rchild);
if(pre!=NULL){
pre->lchild = NULL;
pre->rchild = p;
}
pre = p;
}
}
//单链表打印函数,作为验证
void PrintLinkTree(BiTree T){
BiTree p = T;
while(p!=NULL){
printf("%c", p->data);
p = p->rchild;
}
}
int main(){
BiTree T;
printf("输入二叉树的前序序列,#代表空子树:\n");
CreateBiTree(T);
printf("二叉树创建成功!\n");
LevelOrdertoLinkList(T);
PrintLinkTree(T); //打印生成的单链表
return 0;
}
输出:
输入二叉树的前序序列,#代表空子树:
ABDF###E##C##
二叉树创建成功!
ABCDEF
试题2(王道5.3.3节第17题):
设计算法判断两棵二叉树是否相似。
//判断两个二叉树是否相似
bool Similar(BiTree T1,BiTree T2){
if(T1 != NULL&&T2 == NULL){
return false;
}
else if(T1 == NULL&&T2 != NULL){
return false;
}
else if(T1 == NULL&&T2 == NULL)
return true;
else{
return Similar(T1->lchild, T2->lchild) && Similar(T1->rchild, T2->rchild);
}
}
int main(){
BiTree T1;
printf("输入二叉树T1的前序序列,#代表空子树:\n");
CreateBiTree(T1);
printf("二叉树T1创建成功!\n");
while (getchar() != '\n'); //清空缓存区
BiTree T2;
printf("输入二叉树T2的前序序列,#代表空子树:\n");
CreateBiTree(T2);
printf("二叉树T2创建成功!\n");
printf("%d", Similar(T1, T2));
return 0;
}
输出:
输入二叉树T1的前序序列,#代表空子树:
AB##C##
二叉树T1创建成功!
输入二叉树T2的前序序列,#代表空子树:
DE##F##
二叉树T2创建成功!
1
试题3(王道5.3.3节第18题):
写出在中序线索二叉树中查找指定结点在后序的前驱结点的算法。
我们先把二叉线索树写出来:
//二叉线索树的结构体定义
typedef struct BiTNode{
ElemType data; //数据域
BiTNode *lchild; //指向左子树根节点的指针
BiTNode *rchild; //指向右子树根节点的指针
int ltag, rtag;
}BiTNode, *BiTree;
//建立中序线索二叉树
void InThread(BiTree &T,BiTree &pre){
BiTree p = T;
if(p!=NULL){
InThread(p->lchild,pre);
if(pre!=NULL && pre->rchild==NULL){
pre->rchild = p;
pre->rtag = 1;
}
if(p->lchild == NULL){
p->lchild = pre;
p->ltag = 1;
}
pre = p;
InThread(p->rchild,pre);
}
}
BiTree FirstNode(BiTree T){ //获取中序序列的第一个结点
BiTree p = T;
while(p->ltag == 0){
p = p->lchild;
}
return p;
}
BiTree NextNode(BiTree p){ //求解结点在中序序列下的下一个结点
if(p->rtag = 0)
return FirstNode(p->rchild);
else
return p->rchild;
}
BiTree LastNode(BiTree p){ //求解结点在中序序列下的上一个结点
if(p->ltag =0)
return FirstNode(p->lchild);
else
return p->lchild;
}
//有了前两个函数我们就可以在中序线索二叉树中输出中序遍历序列
void InorderTraverse3(BiTree T){
BiTree p = FirstNode(T);
printf("%c", p->data);
while(p->rchild!=NULL){
p = NextNode(p);
printf("%c", p->data);
}
}
int main(){
BiTree T;
BiTree p = NULL;
printf("输入二叉树的前序序列,#代表空子树:\n");
CreateBiTree(T);
printf("二叉树创建成功!\n");
InThread(T,p);
p = FirstNode(T);
printf("二叉树中序序列的第一个结点是:%c\n", p->data);
printf("二叉树的中序遍历序列是:");
InorderTraverse3(T);
return 0;
}
输出:
输入二叉树的前序序列,#代表空子树:
ABDF###E##C##
二叉树创建成功!
二叉树中序序列的第一个结点是:F
二叉树的中序遍历序列是:FDBEAC
分以下几种情况:
(1)结点有右孩子——右孩子就是后序遍历的前驱结点;
(2)结点只有左孩子——左孩子是后序遍历的前驱结点;
(3)结点没有左右孩子——找中序遍历前驱结点的左孩子结点,找不到就继续往前直到找到有左孩子结点,或者就是第一个结点(左孩子指针为空)返回NULL。
//求在中序线索二叉树中查找指定结点后序遍历的前驱
BiTree FindPast(BiTree p){
if(p->rtag == 0 && p->rchild != NULL)
return p->rchild;
else if(p->ltag == 0)
return p->lchild;
else if(p->ltag == 1 && p->lchild == NULL)
return NULL;
else{ //叶子结点
while(p->ltag == 1 && p->lchild != NULL){
p = p->lchild; //回溯
}
if(p->ltag == 0)
return p->lchild;
else
return NULL;
}
}
int main(){
BiTree T;
BiTree p = NULL;
printf("输入二叉树的前序序列,#代表空子树:\n");
CreateBiTree(T);
printf("二叉树创建成功!\n");
printf("二叉树的中序遍历序列是:");
InOrderTraverse(T);
printf("\n");
printf("二叉树的后序遍历序列是:");
PostOrderTraverse(T);
printf("\n");
InThread(T,p); //线索化
BiTree q = T->rchild; //这行代码找测试结点,实际需要根据用例修改
printf("结点%c的后序遍历序列的前驱结点是:%c", q->data, FindPast(q)->data);
return 0;
}
输出:
输入二叉树的前序序列,#代表空子树:
A#B#C##
二叉树创建成功!
二叉树的中序遍历序列是:ABC
二叉树的后序遍历序列是:CBA
结点B的后序遍历序列的前驱结点是:C
输入二叉树的前序序列,#代表空子树:
AB##C##
二叉树创建成功!
二叉树的中序遍历序列是:BAC
二叉树的后序遍历序列是:BCA
结点C的后序遍历序列的前驱结点是:B
试题4(2014年统考真题):
直接递归:
//前序序列建立二叉树
void CreateBiTree(BiTree &T){
char ch;
scanf("%c", &ch);
if (ch == '#')
T = NULL; //保证是叶结点
else{
T = (BiTree)malloc(sizeof(BiTNode));
T->data = (int)ch; //生成结点(这里偷个懒直接强制转换)
printf("%d", T->data);
CreateBiTree(T->lchild); //构造左子树
CreateBiTree(T->rchild); //构造右子树
}
}
int WPLBiTree(BiTree T,int depth){
if(T==NULL)
return 0;
else
return T->data * depth + WPLBiTree(T->lchild, depth + 1) + WPLBiTree(T->rchild, depth + 1);
}
int main(){
BiTree T;
CreateBiTree(T);
printf("二叉树建立成功!");
printf("二叉树的带权路径长度是:%d", WPLBiTree(T,1));
return 0;
}
输出:
32##4##
515052二叉树建立成功!二叉树的带权路径长度是:255
试题5(2017年统考真题):
此题很显然要利用到二叉树的中序遍历算法。除根结点和叶结点外,遍历到其他结点时在遍历左子树前加上左括号,遍历完右子树后加上右括号。
//本算法给表达式加括号
void InOrderExpression(BiTree T){
if(T!=NULL){
if((T->lchild!=NULL||T->rchild!=NULL))
printf("(");
InOrderExpression(T->lchild);
printf("%c", T->data);
InOrderExpression(T->rchild);
if((T->lchild!=NULL||T->rchild!=NULL))
printf(")");
}
}
int main(){
BiTree T;
printf("输入中缀表达式二叉树的前序序列:");
CreateBiTree(T);
printf("二叉树建立成功!\n");
printf("二叉树的中序序列是:");
InOrderTraverse(T);
printf("\n");
printf("二叉树的中序序列(加括号)是:");
InOrderExpression(T);
printf("\n");
return 0;
}
输出:
输入中缀表达式二叉树的前序序列:*+A##B##*C##-#D##
二叉树建立成功!
二叉树的中序序列是:A+B*C*-D
二叉树的中序序列(加括号)是:((A+B)*(C*(-D)))
试题6(王道5.4.4节第4题):
编程求以孩子兄弟表示法存储的森林的叶子结点数。
分析:二叉树中(1)叶子结点(2)只有右孩子没有左孩子的结点是原森林的叶子结点。随便一种遍历方式,对遍历的结点加以判断即可。
//求森林的叶子结点数
int num = 0;
int Numofleafknots(BiTree T){
if (T!=NULL){
Numofleafknots(T->lchild);
if(T->lchild==NULL&&T->rchild!=NULL)
num = num + 1;
else if(T->lchild==NULL&&T->rchild==NULL)
num = num + 1;
else{
}
Numofleafknots(T->rchild);
}
return num;
}
int main(){
BiTree T;
printf("输入森林对应二叉树的前序序列:");
CreateBiTree(T);
printf("二叉树建立成功!\n");
printf("此森林的叶子结点数是:%d",Numofleafknots(T));
return 0;
}
输出(这里以书上图5.17做验证):
输入森林对应二叉树的前序序列:AB#C#D##EF##GH#I###
二叉树建立成功!
此森林的叶子结点数是:6
试题7(王道5.4.4节第5题):
以孩子兄弟链表为存储结构,请设计递归算法求树的深度。
从树转化成二叉树:左孩子向下走相当于深度+1,右孩子向下走相当于访问同深度兄弟结点。
//求森林的叶子结点数
int DepthofForest(BiTree T){
if(T==NULL)
return 0;
else{
return 1 + DepthofForest(T->lchild) > DepthofForest(T->rchild) ? 1 + DepthofForest(T->lchild) : DepthofForest(T->rchild);
}
}
int main(){
BiTree T;
printf("输入树对应二叉树的前序序列:");
CreateBiTree(T);
printf("二叉树建立成功!\n");
printf("此树的深度是:%d",DepthofForest(T));
return 0;
}
输出(这里以书上图5.14,图5.15做验证):
输入森林对应二叉树的前序序列:RAD#E##B#CFG#H#K#####
二叉树建立成功!
此树的深度是:4
试题8(王道5.4.4节第6题):
已知一棵树的层次序列和每个结点的度,编写算法构造此树的孩子-兄弟链表。
此题借助辅助空间会好做很多:
//构造数组存放层次序列和度的信息
struct Node{
char data;
int degree;
} a[10] = {{'R', 3}, {'A', 2}, {'B', 0}, {'C', 1}, {'D', 0}, {'E', 0}, {'F', 3}, {'G', 0}, {'H', 0}, {'K', 0}}; //仍然以图5.14,5.15为例
BiTree BuildBiTree(Node a[]){
int x = 0; //记录当前结点的孩子
BiTree bitree[10];
for (int i = 0; i < 10;i++){
bitree[i] = (BiTree)malloc(sizeof(BiTNode));
bitree[i]->data = a[i].data;
bitree[i]->lchild = NULL; //初始全为空
bitree[i]->rchild = NULL;
} //这一步生成了10个结点
for (int i = 0; i < 10;i++){
for (int j = 0; j < a[i].degree;j++){
x = x + 1; //此时x指向i的第一个孩子
if(j==0)
bitree[i]->lchild = bitree[x];
else
bitree[x - 1]->rchild = bitree[x];
}
}
return bitree[0];
}
int main(){
printf("此树的深度是:%d\n",DepthofForest(BuildBiTree(a)));
printf("此树对应的二叉树深度是:%d", Depth(BuildBiTree(a)));
return 0;
}
输出:
此树的深度是:4
此树对应的二叉树深度是:8