二叉树高频考点实现01(c/c++)

一、自定义数据结构

#define _CRT_SECURE_NO_WARNINGS
// Exp4-2_BiTree_FrequentlyExam01

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define BI_TREE_NODE_MAX 64


// 二叉树结点的定义
typedef struct _BiNode
{
  char data;
  struct _BiNode* lchild;
  struct _BiNode* rchild;
}BiNode, * BiTree;        // BiTree 完全等价于 BiNode *

二、根据二叉树的完整先序序列,递归创建二叉树的二叉链表存储结构

二叉树各种遍历功能的实现(c/c++)_我龙傲天誓死守护刘波儿的博客-CSDN博客(1)

和(1)的“由完整先序序列递归创建二叉树”不同的是,(1)是在文件中读取完整先序序列,本文是利用引用变量i从数组中读取完整先序序列。

int createBiTreeV1(char completePre[], BiTree& root, int& i)
{
  // static int i = 0;  // 在递归函数中,不要轻易使用static变量
  char ch;
  BiNode* p;

  // 从完整的先序序列中,依次获取各个结点的值(空树为#)
  ch = completePre[i++];

  if ('#' != ch)
  {
    // 开辟空间,构造结点,最后递归创建左右子树
    p = (BiNode*)malloc(sizeof(BiNode));
    p->data = ch;

    root = p;  // 将新结点的地址p返回,作为当前二叉树的根结点

    // 递归创建ch结点的左子树
    int isLeftSuccess = createBiTreeV1(completePre, p->lchild, i);

    // 递归创建ch结点的右子树
    int isRightSuccess = createBiTreeV1(completePre, p->rchild, i);

    if (isLeftSuccess == 1 && isRightSuccess == 1)
      return 1;
    else
      return 0;
  }
  else
  {
    root = NULL;  // 当前二叉树为空,将其根结点的指针设为NULL
    return 1;
  }
}

三、根据二叉树的先序和中序序列,递归创建二叉树的二叉链表存储结构

int createBiTreeV2(char pre[], int preStart, int preEnd,
  char in[], int inStart, int inEnd, BiNode*& root)
{
  char ch;
  int i;
  BiNode* p;

  // 取到二叉树的根结点,即,先序序列中的第一个结点
  if (preStart <= preEnd)
  {
    ch = pre[preStart];
  }
  else // 如果当前先序序列已不存在,这说明该二叉树为空
  {
    root = NULL;
    return 1;
  }

  // 从中序序列中找到根结点ch,用i记录其在中序数组中的下标
  for (i = inStart; i <= inEnd; i++)
  {
    if (in[i] == ch)
      break;
  }

  if (i <= inEnd) // 如果中序序列中找到了根结点
  {
    int leftNodeNum = i - inStart;  // 左子树的结点数
    int rightNodeNum = inEnd - i; // 右子树的结点数

    // 开辟空间,构造结点,最后递归创建左右子树
    p = (BiNode*)malloc(sizeof(BiNode));
    p->data = ch;

    // 将p所指结点设置为根
    root = p;

    // 递归创建左子树
    int isLeftSuccess = createBiTreeV2(pre, preStart + 1, preStart + 1 + leftNodeNum - 1,
      in, inStart, inStart + leftNodeNum - 1, p->lchild);

    int isRightSuccess = createBiTreeV2(pre, preStart + leftNodeNum + 1, preStart + leftNodeNum + 1 + rightNodeNum - 1,
      in, i + 1, i + 1 + rightNodeNum - 1, p->rchild);

    if (isLeftSuccess == 1 && isRightSuccess == 1)
      return 1;
    else
      return 0;
  }
  else  // 当前先序或中序序列有问题,二叉树创建失败
    return 0;
}

四、递归遍历二叉树

// 访问结点函数
void visit(BiTree root) {
    printf("%2c", root->data);
}


// 递归方式先序遍历
void preOrder(BiTree root)
{
    if (root) {
        visit(root);
        preOrder(root->lchild);
        preOrder(root->rchild);
    }
}

// 递归方式中序遍历
void inOrder(BiTree root)
{
    if (root) {
        inOrder(root->lchild);
        visit(root);
        inOrder(root->rchild);
    }
}

// 递归方式后序遍历
void postOrder(BiTree root)
{
    if (root) {
        inOrder(root->lchild);
        inOrder(root->rchild);
        visit(root);
    }
}

五、获得叶子结点数

int getNumOfLeaf(BiTree root)
{
    /*正确但不建议用
    static int count = 0;  //递归函数里最好不要用全局变量
    if (root) {
        if (root->lchild == NULL && root->rchild == NULL) {
            count++;
        }
        getNumOfLeaf(root->lchild);
        getNumOfLeaf(root->rchild);
    }
    return count;*/
    
    if (root == NULL)
        return 0;
    if (root->lchild == NULL && root->rchild == NULL)
        return 1;
    return getNumOfLeaf(root->lchild) + getNumOfLeaf(root->rchild);

}

六、获取度为1的结点数

int getNumOfDegreeOne(BiTree root)
{
    /*可行但不建议
    static int count = 0;
    if (root) {
        if ((root->lchild == NULL && root->rchild != NULL) || (root->lchild != NULL && root->rchild == NULL)) {
            count++;
        }
        getNumOfDegreeOne(root->lchild);
        getNumOfDegreeOne(root->rchild);
        return count;
    }
    return 0;*/
    if (root == NULL)
        return 0;
    if ((root->lchild == NULL && root->rchild != NULL)
        ||( root->lchild != NULL && root->rchild == NULL))
        return 1 + getNumOfDegreeOne(root->lchild) + getNumOfDegreeOne(root->rchild);
    return getNumOfDegreeOne(root->lchild) + getNumOfDegreeOne(root->rchild);
}

七、获取度为2的结点数

int getNumOfDegreeTwo(BiTree root)
{
    if (root == NULL)
        return 0;
    if (root->lchild != NULL && root->rchild != NULL)
        return 1 + getNumOfDegreeTwo(root->lchild) + getNumOfDegreeTwo(root->rchild);
    return getNumOfDegreeTwo(root->lchild) + getNumOfDegreeTwo(root->rchild);
    // 法二:利用n0 = n2 + 1
    // return getNumOfLeaf(root)-1;
}

八、获取总结点数

int getTotalNumOfNodes(BiTree root)
{
    if (root == NULL)
        return 0;
    return 1 + getTotalNumOfNodes(root->lchild) + getTotalNumOfNodes(root->rchild);

}

九、求二叉树的深度/高度

int getHeight(BiTree root)
{
    if (root == NULL) {
        return 0;
    }
    else {
        int l = getHeight(root->lchild);
        int r = getHeight(root->rchild);
        return l > r ? l + 1 : r + 1;
    }
}

十、查找二叉树中的指定结点x,返回该结点的地址,若不存在,则返回NULL

BiNode* getSpecifiedNode(BiTree root, char x)
{
    
    if (root == NULL)
        return NULL;
    if (root->data == x)
        return root;
    // 在左子树查找
    BiNode* l = getSpecifiedNode(root->lchild, x);
    if (l != NULL)  return l;
    //在右子树查找
    BiNode* r = getSpecifiedNode(root->rchild, x);
    return r;

}

十一、获取二叉树中指定结点x所在的层次,若二叉树中不存在x,则返回-1

int getLevelOfNode(BiTree root, char x)
{
    if (root == NULL)
        return -1;
    if (root->data == x)
        return 1;
    // 在左子树查找
    int l = getLevelOfNode(root->lchild, x);
    if (l != -1)  return l+1;
    //在右子树查找
    int r = getLevelOfNode(root->rchild, x);
    if (r != -1)  return r+1;
    return -1;
}

十二、翻转二叉树,即交换所有结点的左右子树

// 遍历每一个结点然后交换其左右孩子
void swapChild(BiTree root)
{
    if (root) {
        BiNode* t;
        t = root->lchild;
        root->lchild = root->rchild;
        root->rchild = t;
        swapChild(root->lchild);
        swapChild(root->rchild);
    }
}

十三、获取指定层次的所有叶子结点

每递归到一个子树,所求层次在子树中就要-1,知道递归至新的root在所所求层次(level=1)上,再判断其是否为叶子结点(root->lchild == NULL && root->rchild == NULL),若是则用leaves[]保存,若不是则继续递进,直到root为空进行回归。

void getNumOfLeafOnSpecifiedLevel(BiTree root, int level, char leaves[], int& i)
{
  // static int i = 0;  // 在递归函数中,不要轻易使用static变量
    if (root == NULL)
        return;
    if (level == 1 && (root->lchild == NULL && root->rchild == NULL))  //递归出口
        leaves[i++] = root->data;
    else
    {
        getNumOfLeafOnSpecifiedLevel(root->lchild, level - 1, leaves, i);
        getNumOfLeafOnSpecifiedLevel(root->rchild, level - 1, leaves, i);
    }
}

十四、判断两棵二叉树是否相等(形状一样,并且所有对应结点的值都相等),相等返回1,不等返回0

小tips:特殊情况优先考虑。

int isSame(BiTree root1, BiTree root2)
{
    if (root1 == NULL && root2 == NULL)
        return 1;
    if (!root1 || !root2)  // 其中一个为空
        return 0;
    if (root1->data == root2->data)  // 如果根结点相等,判断其左右子树是否相等
        return isSame(root1->lchild, root2->lchild) && isSame(root1->rchild, root2->rchild);
    else
        return 0;
}

十五、判断两棵二叉树是否相似(形状一样,但各结点的值并不完全相同)

int isSimilar(BiTree root1, BiTree root2)
{
    if (root1 == NULL && root2 == NULL)
        return 1;
    if (!root1 || !root2)  // 其中一个为空
        return 0;
    return isSimilar(root1->lchild, root2->lchild) && isSimilar(root1->rchild, root2->rchild);


    return 0;
}

十六、递归方式销毁二叉树

void destroy(BiTree root)
{
  if (NULL != root)
  {
    if (NULL != root->lchild)        // 左子树不为空,则递归销毁左子树
      destroy(root->lchild);

    if (NULL != root->rchild)        // 右子树不为空,则递归销毁右子树
      destroy(root->rchild);

    printf("Node %c has been freed!\n", root->data);
    free(root);                    // 最后直接释放根结点
  }
}

十七、功能菜单和主函数

// 功能菜单
void menu()
{
  printf("\n\t************************Binary Linked List************************\n");
  printf("\t*    1--Read data from a file to create a binary tree            *\n");
  printf("\t*    2--PreOrder InOrder and PostOrder traversal by recursion    *\n");
  printf("\t*    3--Get the number of all kinds of nodes                     *\n");
  printf("\t*    4--Get the depth or height of the BiTree                    *\n");
  printf("\t*    5--Get the specified node(left and right children, level)   *\n");
  printf("\t*    6--Swap all left and right subtrees                         *\n");
  printf("\t*    7--Get the number of leaf nodes on specified level          *\n");
  printf("\t*    8--Judge if two trees are same                              *\n");
  printf("\t*    9--Judge if two trees are similar                           *\n");
  printf("\t*    10--Destroy the entire binary tree                          *\n");
  printf("\t*    11--Clear screen                                            *\n");
  printf("\t*    0--Exit program                                             *\n");
  printf("\t******************************************************************\n");
  printf("\tPlease select a menu item:");
}

int main()
{
  int choice;
  char c;
  FILE* fpFrom;
  BiTree root = NULL;        // BiTree 完全等价于 BiNode *

  system("chcp 65001");  // 设置window控制台(CMD或命令行窗口)为UTF-8格式


  while (1)
  {
    menu();
    scanf("%d", &choice);

    switch (choice)
    {
    case 1:
      if (NULL != root)
        printf("The current binary tree is not empty, please destroy it before rebuild!\n");
      else
      {
        // 因为createBiTree()函数递归时要不断从文件中读取字符,所以先打开文件
        // 如果在createBiTree()函数中每读一个字符,就打开并关闭文件一次,则效率太低
        fpFrom = fopen("BT.dat", "r");

        if (fpFrom == NULL)
        {
          printf("File BT.dat containing PreOrdered and InOrdered sequence cannot be opened, binary tree creation failed!\n");
          break;
        }

        // 二叉树的先序和中序序列
        char pre[BI_TREE_NODE_MAX], in[BI_TREE_NODE_MAX];
        fscanf(fpFrom, "%s", pre);    // 先读先序序列
        fscanf(fpFrom, "%s", in);    // 再读中序序列
        fclose(fpFrom);

        int nodeNum = strlen(pre);    // 得到二叉树中的结点数

        // 通过先序和中序序列,恢复二叉树的二叉链表存储结构
        int ret = createBiTreeV2(pre, 0, nodeNum - 1, in, 0, nodeNum - 1, root);
        if (ret == 1)
          printf("Binary tree created successfully!\n");
        else
          printf("Binary tree created failed!\n");
      }
      break;

    case 2:
      if (NULL != root)
      {
        printf("The PreOrdered sequence is as follows:");
        preOrder(root);

        printf("\nThe InOrdered sequence is as follows:");
        inOrder(root);

        printf("\nThe PostOrdered sequence is as follows:");
        postOrder(root);

        printf("\n");
      }
      else
        printf("The current binary tree is empty, please create the binary tree first!\n");
      break;

    case 3:   // 获得各种结点的数量(度为0,度为1,度为2,总结点数)
      if (NULL != root)
      {
        printf("The number of all kinds of nodes is as follows:\n");
        int leaf = getNumOfLeaf(root);    // 获得度为0的结点数
        int degreeOne = getNumOfDegreeOne(root);    // 获得度为1的结点数
        int degreeTwo = getNumOfDegreeTwo(root);    // 获得度为2的结点数
        int total = getTotalNumOfNodes(root);    // 获得结点的总数
        printf("Number of leaf = %d\n", leaf);
        printf("Number of degree one = %d\n", degreeOne);
        printf("Number of degree two = %d\n", degreeTwo);
        printf("Number of all nodes = %d\n", total);
        printf("\n");
      }
      else
        printf("The current binary tree is empty, please create the binary tree first!\n");
      break;

    case 4:
      if (NULL != root)
      {
        int height = getHeight(root);  // 获得二叉树的深度或高度
        printf("The depth or height of the BiTree is %d.\n", height);
        printf("\n");
      }
      else
        printf("The current binary tree is empty, please create the binary tree first!\n");
      break;

    case 5:
      if (NULL != root)
      {
        printf("Please enter the value of the node you are looking for:\n");
        // the buffer needs to be emptied
        char x;
        while ((x = getchar()) != '\n' && x != EOF);
        scanf("%c", &x);

        BiNode* p = getSpecifiedNode(root, x);  // 查找二叉树中的指定结点
        if (p == NULL)
        {
          printf("There is not exist node %c in the binary tree. \n", x);
        }
        else
        {
          if (p->lchild != NULL)
          {
            printf("The left child of %c is %c. \n", x, p->lchild->data);
          }
          else
          {
            printf("The left child of %c is not exist. \n", x);
          }

          if (p->rchild != NULL)
          {
            printf("The right child of %c is %c. \n", x, p->rchild->data);
          }
          else
          {
            printf("The right child of %c is not exist. \n", x);
          }
        }

        int level = getLevelOfNode(root, x);  // 获取二叉树中指定结点所在的层次
        if (level != -1)
        {
          printf("The level of %c is %d. \n", x, level);
        }
        printf("\n");
      }
      else
        printf("The current binary tree is empty, please create the binary tree first!\n");
      break;

    case 6:
      if (NULL != root)
      {
        swapChild(root);   // 翻转二叉树,交换所有结点的左右子树
        printf("The binary tree was flipped successfully!\n");
        printf("\n");
      }
      else
        printf("The current binary tree is empty, please create the binary tree first!\n");
      break;

    case 7:
      if (NULL != root)
      {
        char leaves[BI_TREE_NODE_MAX], c;
        int leavesNum, level;

        printf("Please enter the level:\n");
        scanf("%d", &level);
        // 防止用户输入的不是整数,清空一下缓冲区
        while ((c = getchar()) != '\n' && c != EOF);

        leavesNum = 0;
        getNumOfLeafOnSpecifiedLevel(root, level, leaves, leavesNum);   // 获得指定层次的所有叶子结点

        if (leavesNum > 0)
        {
          printf("All the leaves at level %d are as follows:\n", level);
          for (int i = 0; i < leavesNum; i++)
          {
            printf("%3c", leaves[i]);
          }
          printf("\n");
        }

        printf("The level %d have %d leaf nodes.\n", level, leavesNum);
        printf("\n");
      }
      else
        printf("The current binary tree is empty, please create the binary tree first!\n");
      break;

    case 8:  // 判断两棵二叉树是否相等
    {    // 此对大括号相当于构造一个命名空间,不要去掉
      if (root == NULL)
      {
        printf("The current binary tree(BT.dat) is empty, you may need to create it first!\n");
      }

      BiTree root2 = NULL;
      FILE* fpFrom = fopen("BT2.dat", "r");

      if (fpFrom == NULL)
      {
        printf("File BT2.dat containing the complete PreOrdered sequence cannot be opened, binary tree creation failed!\n");
        break;
      }

      // 读取二叉树的完整先序序列
      char completePre[BI_TREE_NODE_MAX * 2];
      fscanf(fpFrom, "%s", completePre);    // 读取二叉树的完整先序序列
      fclose(fpFrom);

      // 通过二叉树的完整先序序列,创建二叉树的二叉链表存储结构
      int idx = 0;  // 只是表明createBiTreeV1函数中完整先序的0号单元为根,无其它意义
      int ret = createBiTreeV1(completePre, root2, idx);
      if (ret == 1)
      {
        printf("The second binary tree(BT2.dat) created successfully!\n");

        int flag = isSame(root, root2);
        if (flag == 1)
        {
          printf("The two binary trees(BT.dat & BT2.dat) are same!\n");
        }
        else
        {
          printf("The two binary trees(BT.dat & BT2.dat) are NOT same!\n");
        }
      }
      else
      {
        printf("The second binary tree(BT2.dat) created failed!\n");
      }

      if (root2 != NULL)
        printf("Destroying binary tree %c ......\n", root2->data);
      destroy(root2);  // 无论创建成功或失败,最后都将已经开辟的结点空间回收,防止内存泄漏
      root2 = NULL;   // 销毁之后,该二叉树为空,需要将根结点的指针设置为NULL
      break;
    }

    case 9:  // 判断两棵二叉树是否相似
    {    // 此对大括号相当于构造一个命名空间,不要去掉
      if (root == NULL)
      {
        printf("The current binary tree(BT.dat) is empty, you may need to create it first!\n");
      }

      BiTree root3 = NULL;
      FILE* fpFrom = fopen("BT3.dat", "r");

      if (fpFrom == NULL)
      {
        printf("File BT3.dat containing the complete PreOrdered sequence cannot be opened, binary tree creation failed!\n");
        break;
      }

      // 读取二叉树的完整先序序列
      char completePre[BI_TREE_NODE_MAX * 2];
      fscanf(fpFrom, "%s", completePre);    // 读取二叉树的完整先序序列
      fclose(fpFrom);

      // 通过二叉树的完整先序序列,创建二叉树的二叉链表存储结构
      int idx = 0;  // 只是表明createBiTreeV1函数中完整先序的0号单元为根,无其它意义
      int ret = createBiTreeV1(completePre, root3, idx);
      if (ret == 1)
      {
        printf("The third binary tree(BT3.dat) created successfully!\n");

        int flag = isSimilar(root, root3);
        if (flag == 1)
        {
          printf("The two binary trees(BT.dat & BT3.dat) are similar!\n");
        }
        else
        {
          printf("The two binary trees(BT.dat & BT3.dat) are NOT similar!\n");
        }
      }
      else
      {
        printf("The third binary tree(BT3.dat) created failed!\n");
      }

      if (root3 != NULL)
        printf("Destroying binary tree %c ......\n", root3->data);
      destroy(root3);  // 无论创建成功或失败,最后都将已经开辟的结点空间回收,防止内存泄漏
      root3 = NULL;   // 销毁之后,该二叉树为空,需要将根结点的指针设置为NULL
      break;
    }

    case 10:
      if (NULL != root)
      {
        destroy(root);
        root = NULL;
        printf("The binary tree destroyed successfully!\n");
      }
      else
        printf("The current binary tree is empty, no need to destroy!\n");
      break;

    case 11:
      system("cls");
      break;

    case 0:
      exit(0);
      break;

    default:
      // If the user enters an alphabetic menu item instead of an integer, 
      // the buffer needs to be emptied
      while ((c = getchar()) != '\n' && c != EOF);
      printf("The menu item you entered does not exist, please select it again!\n");
    }
  }
  return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值