二叉树高频考点的实现02

一、自定义数据结构

#define _CRT_SECURE_NO_WARNINGS
// Exp4-3_BiTree_FrequentlyExam02

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

#define BI_TREE_NODE_MAX 64
#define QUEUE_MAX_LENGTH 64


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

// 固定长度的循序顺序队列结构体
typedef struct
{
  BiTree data[QUEUE_MAX_LENGTH];
  int front;
  int rear;
} SeqQueue;

二、自定义队列函数

// 判断队列是否为空
int queueIsEmpty(SeqQueue queue)
{
  if (queue.front == queue.rear)
    return 1;
  else
    return 0;
}

// 判断队列是否为满
int queueIsFull(SeqQueue queue)
{
  if (queue.front == (queue.rear + 1) % QUEUE_MAX_LENGTH)
    return 1;
  else
    return 0;
}

// 当前队列中有多少个元素
int getElemNum(SeqQueue queue)
{
  return (queue.rear - queue.front + QUEUE_MAX_LENGTH) % QUEUE_MAX_LENGTH;
}

// 初始化为空队列
void initQueue(SeqQueue& queue)
{
  queue.front = queue.rear = QUEUE_MAX_LENGTH - 1;
}

/* 进队一个元素 */
int inQueue(SeqQueue& queue, BiTree e)
{
  if (1 == queueIsFull(queue))
    return 0;            // 队列已满,无法进队
  else
  {
    queue.rear = (queue.rear + 1) % QUEUE_MAX_LENGTH;
    queue.data[queue.rear] = e;

    return 1;            // 进队成功
  }
}

/* 出队一个元素 */
int outQueue(SeqQueue& queue, BiTree& e)
{
  if (1 == queueIsEmpty(queue))
    return 0;            // 队列已空,无法出队
  else
  {
    queue.front = (queue.front + 1) % QUEUE_MAX_LENGTH;
    e = queue.data[queue.front];

    return 1;            // 出队成功
  }
}

/* 读取队头和队尾元素的信息(不出队列) */
int getFrontRear(SeqQueue queue, BiTree& ef, BiTree& er)
{
  if (1 == queueIsEmpty(queue))
    return 0;            // 队列已空,无队头和队尾
  else
  {
    ef = queue.data[queue.front + 1];
    er = queue.data[queue.rear];

    return 1;
  }
}

三、二叉树有关函数

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

// 根据二叉树的完整先序序列,递归创建二叉树的二叉链表存储结构
int createBiTreeV1(char completePre[], BiTree& root, int& i)
{
  // static int i = 0;  // 在递归函数中,不要轻易使用static变量
  char ch;
  BiNode* p;

  // 从完整的先序序列中,依次获取各个结点的值(空树为#)
  // ch = fgetc(fp);
  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;
  }
}

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

// 根据二叉树的先序和中序序列,递归创建二叉树的二叉链表存储结构
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
  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;
}

3.递归遍历

// 递归方式先序遍历
void preOrder(BiTree root)
{
  if (NULL != root)
  {
    printf("%2c", root->data);
    preOrder(root->lchild);
    preOrder(root->rchild);
  }
}

// 递归方式中序遍历
void inOrder(BiTree root)
{
  if (NULL != root)
  {
    inOrder(root->lchild);
    printf("%2c", root->data);
    inOrder(root->rchild);
  }
}

// 递归方式后序遍历
void postOrder(BiTree root)
{
  if (NULL != root)
  {
    postOrder(root->lchild);
    postOrder(root->rchild);
    printf("%2c", root->data);
  }
}

4.判断两个结点x和y是否构成兄弟关系

// Function3--判断两个结点x和y是否构成兄弟关系
int isBrothers(BiTree root, char x, char y)
{
    if (root == NULL)
        return 0;
    if (root->lchild != NULL && root->rchild != NULL)
    {
        if ((root->lchild->data == x && root->rchild->data == y)
            || (root->lchild->data == y && root->rchild->data == x))
            return 1;
    }
    int lRet = isBrothers(root->lchild, x, y);
    int rRet = isBrothers(root->rchild, x, y);
    if (lRet == 1 || rRet == 1)
        return 1;
    else
        return 0;
}

5.判断结点z是否存在?若为根,则返回1;若存在左子树中,则返回2;若存在右子树中,则返回3;若不存在,则返回0

// Function4--判断结点z是否存在?若为根,则返回1;若存在左子树中,则返回2;若存在右子树中,则返回3;若不存在,则返回0。
int getRegionOfNode(BiTree root, char z)
{
    if (root == NULL)
        return 0;
    if (root->data == z)
        return 1;
    int lRet = getRegionOfNode(root->lchild, z);
    if (lRet != 0)
        return 2;

    int rRet = getRegionOfNode(root->rchild, z);
    if (rRet != 0)
        return 3;
    return 0;
}

6.获得两个结点x和y的最近公共祖先,若x或y不存在,或者不存在公共祖先则返回NULL

BiNode* getNearestCommonAncestor(BiTree root, char x, char y)
{
    if (root == NULL)
        return NULL;

    int xAncestor = getRegionOfNode(root, x);
    int yAncestor = getRegionOfNode(root, y);

    if ((xAncestor == 1 && yAncestor != 0) ||
        (yAncestor == 1 && xAncestor != 0) ||
        (xAncestor == 2 && yAncestor == 3) ||
        (yAncestor == 2 && xAncestor == 3))  
        return root;

    if (xAncestor == 2 && yAncestor == 2)
        return getNearestCommonAncestor(root->lchild, x, y);
    if (xAncestor == 3 && yAncestor == 3)
        return getNearestCommonAncestor(root->rchild, x, y);
    return NULL;
}

7.获取结点x的所有子孙,依次存入desc数组,变量 i 带回存入子孙的个数

void saveDescendantNode(BiTree root, BiTree desc[], int& i)
{
    // static int i = 0;
    if (root == NULL)
        return;
    desc[i++] = root;
    saveDescendantNode(root->lchild, desc, i);
    saveDescendantNode(root->rchild, desc, i);
}

8.获取结点x的所有子孙,返回子孙结点的个数;若结点x不存在,则返回-1;若结点x为叶子,则返回0

int getAllDescendants(BiTree root, char x, BiTree desc[])
{
    int count = 0;
    if (root == NULL)
        return -1;
    if (root->data == x)
    {
        saveDescendantNode(root->lchild, desc, count);
        saveDescendantNode(root->rchild, desc, count);
        return count;
    }
    int lNum = getAllDescendants(root->lchild, x, desc);
    if (lNum >= 0)
        return lNum;
    int rNum = getAllDescendants(root->rchild, x, desc);
    if (rNum >= 0)
        return rNum;
    return -1;

}

9.判断root是否为完全二叉树;若是则返回1,否则返回0

int isCompleteBiTree(BiTree root)
{
  SeqQueue Q;
  BiNode* p = NULL;
  int flag = 0; 
  if (root == NULL)
    return 1;    // 空树看成完全二叉树
  
  initQueue(Q);
  inQueue(Q, root);
  while (!queueIsEmpty(Q))
  {
      outQueue(Q, p);
      //flag = 1 说明前面有结点孩子为空
      if (flag == 1 && (p->lchild != NULL || p->rchild != NULL))
          return 0;

      if (p->lchild != NULL)
          inQueue(Q, p->lchild);
      else
          flag = 1;

      if (p->rchild != NULL)
      {
          if (p->lchild == NULL)
              return 0;
          inQueue(Q, p->rchild);
      }
      else
          flag = 1;
  }
  return 1;


}

10.递归方式销毁二叉树

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

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

    printf("%c node 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--Check whether the specified two nodes are brothers      *\n");
  printf("\t*    4--Get the nearest common ancestor of two specified nodes  *\n");
  printf("\t*    5--Output all descendants of the specified node            *\n");
  printf("\t*    6--Judge whether a binary tree is a complete binary tree   *\n");
  printf("\t*    7--Destroy the entire binary tree                          *\n");
  printf("\t*    8--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 it first!\n");
      break;

    case 3:
      if (NULL != root)
      {
        char x, y;
        printf("Please enter values for both nodes(Separate with a space):");
        while ((x = getchar()) != '\n' && x != EOF);
        scanf("%c %c", &x, &y);

        int ret = isBrothers(root, x, y);  // 判断两个结点x和y是否构成兄弟关系
        if (ret == 1)
        {
          printf("%c and %c are brothers!\n", x, y);
        }
        else
        {
          printf("%c and %c are NOT brothers!\n", x, y);
        }
      }
      else
        printf("The current binary tree is empty, please create it first!\n");
      break;

    case 4:
      if (NULL != root)
      {
        char x, y;
        printf("Please enter values for both nodes(Separate with a space):");
        while ((x = getchar()) != '\n' && x != EOF);
        scanf("%c %c", &x, &y);

        BiNode* p = getNearestCommonAncestor(root, x, y);  // 求两个结点x和y的最近公共祖先
        if (p != NULL)
        {
          printf("The nearest common ancestor of nodes %c and %c is %c!\n", x, y, p->data);
        }
        else
        {
          printf("Nodes %c and %c have no common ancestor!\n", x, y);
        }
      }
      else
        printf("The current binary tree is empty, please create it first!\n");
      break;

    case 5:
      if (NULL != root)
      {
        char x;
        printf("Please enter the value of a node:");
        while ((x = getchar()) != '\n' && x != EOF);
        scanf("%c", &x);

        BiTree desc[BI_TREE_NODE_MAX];
        // 获取结点x的所有子孙,子孙的数量为返回值num,每个子孙结点的地址存放于desc数组
        int num = getAllDescendants(root, x, desc);
        if (num > 0)
        {
          printf("All the descendants of node %c are as follows:\n", x);
          for (int i = 0; i < num; i++)
          {
            printf("%3c", desc[i]->data);
          }
          printf("\n");
        }
        else if (num == 0)
        {
          printf("Node %c is a leaf node!\n", x);
        }
        else
        {
          printf("Node %c does not exist!\n", x);
        }
      }
      else
        printf("The current binary tree is empty, please create it first!\n");
      break;

    case 6:
      if (NULL != root)
      {
        // 判断root是否为完全二叉树
        int flag = isCompleteBiTree(root);
        if (flag == 1)
        {
          printf("The current binary tree is a complete binary tree!\n");
        }
        else
        {
          printf("The current binary tree is NOT a complete binary tree!\n");
        }
      }
      else
        printf("The current binary tree is empty, please create it first!\n");
      break;

    case 7:
      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 8:
      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
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值