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


    试题1(王道5.3.3节第16题):

    设计算法将二叉树的叶结点按从左到右的顺序连成单链表,连接时使用叶结点的右指针域存放单链表指针。

    借助遍历算法完成:

    1. //根据二叉树层次遍历序列构造单链表
    2. void LevelOrdertoLinkList(BiTree &T){
    3. Queue q;
    4. InitQueue(q);
    5. BiTree p = T;
    6. BiTree pre = NULL;
    7. InsertQueue(q, p);
    8. while(!IsQueueEmpty(q)){
    9. p = DeleteQueue(q, p);
    10. if(p->lchild!=NULL)
    11. InsertQueue(q, p->lchild);
    12. if(p->rchild!=NULL)
    13. InsertQueue(q, p->rchild);
    14. if(pre!=NULL){
    15. pre->lchild = NULL;
    16. pre->rchild = p;
    17. }
    18. pre = p;
    19. }
    20. }
    21. //单链表打印函数,作为验证
    22. void PrintLinkTree(BiTree T){
    23. BiTree p = T;
    24. while(p!=NULL){
    25. printf("%c", p->data);
    26. p = p->rchild;
    27. }
    28. }
    29. int main(){
    30. BiTree T;
    31. printf("输入二叉树的前序序列,#代表空子树:\n");
    32. CreateBiTree(T);
    33. printf("二叉树创建成功!\n");
    34. LevelOrdertoLinkList(T);
    35. PrintLinkTree(T); //打印生成的单链表
    36. return 0;
    37. }

    输出:

    1. 输入二叉树的前序序列,#代表空子树:
    2. ABDF###E##C##
    3. 二叉树创建成功!
    4. ABCDEF

    试题2(王道5.3.3节第17题):

    设计算法判断两棵二叉树是否相似。

    1. //判断两个二叉树是否相似
    2. bool Similar(BiTree T1,BiTree T2){
    3. if(T1 != NULL&&T2 == NULL){
    4. return false;
    5. }
    6. else if(T1 == NULL&&T2 != NULL){
    7. return false;
    8. }
    9. else if(T1 == NULL&&T2 == NULL)
    10. return true;
    11. else{
    12. return Similar(T1->lchild, T2->lchild) && Similar(T1->rchild, T2->rchild);
    13. }
    14. }
    15. int main(){
    16. BiTree T1;
    17. printf("输入二叉树T1的前序序列,#代表空子树:\n");
    18. CreateBiTree(T1);
    19. printf("二叉树T1创建成功!\n");
    20. while (getchar() != '\n'); //清空缓存区
    21. BiTree T2;
    22. printf("输入二叉树T2的前序序列,#代表空子树:\n");
    23. CreateBiTree(T2);
    24. printf("二叉树T2创建成功!\n");
    25. printf("%d", Similar(T1, T2));
    26. return 0;
    27. }

    输出:

    1. 输入二叉树T1的前序序列,#代表空子树:
    2. AB##C##
    3. 二叉树T1创建成功!
    4. 输入二叉树T2的前序序列,#代表空子树:
    5. DE##F##
    6. 二叉树T2创建成功!
    7. 1

    试题3(王道5.3.3节第18题):

    写出在中序线索二叉树中查找指定结点在后序的前驱结点的算法。

    我们先把二叉线索树写出来:

    1. //二叉线索树的结构体定义
    2. typedef struct BiTNode{
    3. ElemType data; //数据域
    4. BiTNode *lchild; //指向左子树根节点的指针
    5. BiTNode *rchild; //指向右子树根节点的指针
    6. int ltag, rtag;
    7. }BiTNode, *BiTree;
    8. //建立中序线索二叉树
    9. void InThread(BiTree &T,BiTree &pre){
    10. BiTree p = T;
    11. if(p!=NULL){
    12. InThread(p->lchild,pre);
    13. if(pre!=NULL && pre->rchild==NULL){
    14. pre->rchild = p;
    15. pre->rtag = 1;
    16. }
    17. if(p->lchild == NULL){
    18. p->lchild = pre;
    19. p->ltag = 1;
    20. }
    21. pre = p;
    22. InThread(p->rchild,pre);
    23. }
    24. }
    25. BiTree FirstNode(BiTree T){ //获取中序序列的第一个结点
    26. BiTree p = T;
    27. while(p->ltag == 0){
    28. p = p->lchild;
    29. }
    30. return p;
    31. }
    32. BiTree NextNode(BiTree p){ //求解结点在中序序列下的下一个结点
    33. if(p->rtag = 0)
    34. return FirstNode(p->rchild);
    35. else
    36. return p->rchild;
    37. }
    38. BiTree LastNode(BiTree p){ //求解结点在中序序列下的上一个结点
    39. if(p->ltag =0)
    40. return FirstNode(p->lchild);
    41. else
    42. return p->lchild;
    43. }
    44. //有了前两个函数我们就可以在中序线索二叉树中输出中序遍历序列
    45. void InorderTraverse3(BiTree T){
    46. BiTree p = FirstNode(T);
    47. printf("%c", p->data);
    48. while(p->rchild!=NULL){
    49. p = NextNode(p);
    50. printf("%c", p->data);
    51. }
    52. }
    53. int main(){
    54. BiTree T;
    55. BiTree p = NULL;
    56. printf("输入二叉树的前序序列,#代表空子树:\n");
    57. CreateBiTree(T);
    58. printf("二叉树创建成功!\n");
    59. InThread(T,p);
    60. p = FirstNode(T);
    61. printf("二叉树中序序列的第一个结点是:%c\n", p->data);
    62. printf("二叉树的中序遍历序列是:");
    63. InorderTraverse3(T);
    64. return 0;
    65. }

    输出:

    1. 输入二叉树的前序序列,#代表空子树:
    2. ABDF###E##C##
    3. 二叉树创建成功!
    4. 二叉树中序序列的第一个结点是:F
    5. 二叉树的中序遍历序列是:FDBEAC

    分以下几种情况:

    (1)结点有右孩子——右孩子就是后序遍历的前驱结点;

    (2)结点只有左孩子——左孩子是后序遍历的前驱结点;

    (3)结点没有左右孩子——找中序遍历前驱结点的左孩子结点,找不到就继续往前直到找到有左孩子结点,或者就是第一个结点(左孩子指针为空)返回NULL。

    1. //求在中序线索二叉树中查找指定结点后序遍历的前驱
    2. BiTree FindPast(BiTree p){
    3. if(p->rtag == 0 && p->rchild != NULL)
    4. return p->rchild;
    5. else if(p->ltag == 0)
    6. return p->lchild;
    7. else if(p->ltag == 1 && p->lchild == NULL)
    8. return NULL;
    9. else{ //叶子结点
    10. while(p->ltag == 1 && p->lchild != NULL){
    11. p = p->lchild; //回溯
    12. }
    13. if(p->ltag == 0)
    14. return p->lchild;
    15. else
    16. return NULL;
    17. }
    18. }
    19. int main(){
    20. BiTree T;
    21. BiTree p = NULL;
    22. printf("输入二叉树的前序序列,#代表空子树:\n");
    23. CreateBiTree(T);
    24. printf("二叉树创建成功!\n");
    25. printf("二叉树的中序遍历序列是:");
    26. InOrderTraverse(T);
    27. printf("\n");
    28. printf("二叉树的后序遍历序列是:");
    29. PostOrderTraverse(T);
    30. printf("\n");
    31. InThread(T,p); //线索化
    32. BiTree q = T->rchild; //这行代码找测试结点,实际需要根据用例修改
    33. printf("结点%c的后序遍历序列的前驱结点是:%c", q->data, FindPast(q)->data);
    34. return 0;
    35. }

    输出:

    1. 输入二叉树的前序序列,#代表空子树:
    2. A#B#C##
    3. 二叉树创建成功!
    4. 二叉树的中序遍历序列是:ABC
    5. 二叉树的后序遍历序列是:CBA
    6. 结点B的后序遍历序列的前驱结点是:C
    7. 输入二叉树的前序序列,#代表空子树:
    8. AB##C##
    9. 二叉树创建成功!
    10. 二叉树的中序遍历序列是:BAC
    11. 二叉树的后序遍历序列是:BCA
    12. 结点C的后序遍历序列的前驱结点是:B

    试题4(2014年统考真题):

    直接递归:

    1. //前序序列建立二叉树
    2. void CreateBiTree(BiTree &T){
    3. char ch;
    4. scanf("%c", &ch);
    5. if (ch == '#')
    6. T = NULL; //保证是叶结点
    7. else{
    8. T = (BiTree)malloc(sizeof(BiTNode));
    9. T->data = (int)ch; //生成结点(这里偷个懒直接强制转换)
    10. printf("%d", T->data);
    11. CreateBiTree(T->lchild); //构造左子树
    12. CreateBiTree(T->rchild); //构造右子树
    13. }
    14. }
    15. int WPLBiTree(BiTree T,int depth){
    16. if(T==NULL)
    17. return 0;
    18. else
    19. return T->data * depth + WPLBiTree(T->lchild, depth + 1) + WPLBiTree(T->rchild, depth + 1);
    20. }
    21. int main(){
    22. BiTree T;
    23. CreateBiTree(T);
    24. printf("二叉树建立成功!");
    25. printf("二叉树的带权路径长度是:%d", WPLBiTree(T,1));
    26. return 0;
    27. }

    输出:

    1. 32##4##
    2. 515052二叉树建立成功!二叉树的带权路径长度是:255

    试题5(2017年统考真题):

    此题很显然要利用到二叉树的中序遍历算法。除根结点和叶结点外,遍历到其他结点时在遍历左子树前加上左括号,遍历完右子树后加上右括号。

    1. //本算法给表达式加括号
    2. void InOrderExpression(BiTree T){
    3. if(T!=NULL){
    4. if((T->lchild!=NULL||T->rchild!=NULL))
    5. printf("(");
    6. InOrderExpression(T->lchild);
    7. printf("%c", T->data);
    8. InOrderExpression(T->rchild);
    9. if((T->lchild!=NULL||T->rchild!=NULL))
    10. printf(")");
    11. }
    12. }
    13. int main(){
    14. BiTree T;
    15. printf("输入中缀表达式二叉树的前序序列:");
    16. CreateBiTree(T);
    17. printf("二叉树建立成功!\n");
    18. printf("二叉树的中序序列是:");
    19. InOrderTraverse(T);
    20. printf("\n");
    21. printf("二叉树的中序序列(加括号)是:");
    22. InOrderExpression(T);
    23. printf("\n");
    24. return 0;
    25. }

    输出:

    1. 输入中缀表达式二叉树的前序序列:*+A##B##*C##-#D##
    2. 二叉树建立成功!
    3. 二叉树的中序序列是:A+B*C*-D
    4. 二叉树的中序序列(加括号)是:((A+B)*(C*(-D)))

    试题6(王道5.4.4节第4题):

    编程求以孩子兄弟表示法存储的森林的叶子结点数。

    分析:二叉树中(1)叶子结点(2)只有右孩子没有左孩子的结点是原森林的叶子结点。随便一种遍历方式,对遍历的结点加以判断即可。

    1. //求森林的叶子结点数
    2. int num = 0;
    3. int Numofleafknots(BiTree T){
    4. if (T!=NULL){
    5. Numofleafknots(T->lchild);
    6. if(T->lchild==NULL&&T->rchild!=NULL)
    7. num = num + 1;
    8. else if(T->lchild==NULL&&T->rchild==NULL)
    9. num = num + 1;
    10. else{
    11. }
    12. Numofleafknots(T->rchild);
    13. }
    14. return num;
    15. }
    16. int main(){
    17. BiTree T;
    18. printf("输入森林对应二叉树的前序序列:");
    19. CreateBiTree(T);
    20. printf("二叉树建立成功!\n");
    21. printf("此森林的叶子结点数是:%d",Numofleafknots(T));
    22. return 0;
    23. }

    输出(这里以书上图5.17做验证):

    1. 输入森林对应二叉树的前序序列:AB#C#D##EF##GH#I###
    2. 二叉树建立成功!
    3. 此森林的叶子结点数是:6

    试题7(王道5.4.4节第5题):

    以孩子兄弟链表为存储结构,请设计递归算法求树的深度。

    从树转化成二叉树:左孩子向下走相当于深度+1,右孩子向下走相当于访问同深度兄弟结点。

    1. //求森林的叶子结点数
    2. int DepthofForest(BiTree T){
    3. if(T==NULL)
    4. return 0;
    5. else{
    6. return 1 + DepthofForest(T->lchild) > DepthofForest(T->rchild) ? 1 + DepthofForest(T->lchild) : DepthofForest(T->rchild);
    7. }
    8. }
    9. int main(){
    10. BiTree T;
    11. printf("输入树对应二叉树的前序序列:");
    12. CreateBiTree(T);
    13. printf("二叉树建立成功!\n");
    14. printf("此树的深度是:%d",DepthofForest(T));
    15. return 0;
    16. }

    输出(这里以书上图5.14,图5.15做验证):

    1. 输入森林对应二叉树的前序序列:RAD#E##B#CFG#H#K#####
    2. 二叉树建立成功!
    3. 此树的深度是:4

    试题8(王道5.4.4节第6题):

    已知一棵树的层次序列和每个结点的度,编写算法构造此树的孩子-兄弟链表。

    此题借助辅助空间会好做很多:

    1. //构造数组存放层次序列和度的信息
    2. struct Node{
    3. char data;
    4. int degree;
    5. } 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为例
    6. BiTree BuildBiTree(Node a[]){
    7. int x = 0; //记录当前结点的孩子
    8. BiTree bitree[10];
    9. for (int i = 0; i < 10;i++){
    10. bitree[i] = (BiTree)malloc(sizeof(BiTNode));
    11. bitree[i]->data = a[i].data;
    12. bitree[i]->lchild = NULL; //初始全为空
    13. bitree[i]->rchild = NULL;
    14. } //这一步生成了10个结点
    15. for (int i = 0; i < 10;i++){
    16. for (int j = 0; j < a[i].degree;j++){
    17. x = x + 1; //此时x指向i的第一个孩子
    18. if(j==0)
    19. bitree[i]->lchild = bitree[x];
    20. else
    21. bitree[x - 1]->rchild = bitree[x];
    22. }
    23. }
    24. return bitree[0];
    25. }
    26. int main(){
    27. printf("此树的深度是:%d\n",DepthofForest(BuildBiTree(a)));
    28. printf("此树对应的二叉树深度是:%d", Depth(BuildBiTree(a)));
    29. return 0;
    30. }

    输出:

    1. 此树的深度是:4
    2. 此树对应的二叉树深度是:8
  • 相关阅读:
    大数据杂谈
    多态day02
    WhatsApp+SaleSmartly自动化,还有这些惊喜是你不知道的!
    OSPF —— LSA-3
    回顾总结之数据结构:3 链表
    MYSQL的主从复制
    js逆向-5-字体反爬
    Jquery-todolist案例
    执行autoreconf -fi的过程报错
    重新安装电脑系统Win10步骤教程
  • 原文地址:https://blog.csdn.net/qq_54708219/article/details/133795040