36.树与二叉树练习(2)(王道第5章综合练习)

试题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
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北京地铁1号线

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值