2021SCAU数据结构复习 实验四(二叉树专题)

题1:8606 二叉树的构建及遍历操作

题目描述

Description 构造二叉链表表示的二叉树:按先序次序输入二叉树中结点的值(一个字符),’#'字符表示空树,构造二叉链表表示的二叉树T;再输出三种遍历序列。本题只给出部分代码,请补全内容。
#include “stdio.h”
#include “malloc.h”
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;

typedef char ElemType;
typedef struct BiTNode{
ElemType data;
struct BiTNode *lchild,*rchild;//左右孩子指针
} BiTNode,*BiTree;

Status CreateBiTree(BiTree &T) { // 算法6.4
// 按先序次序输入二叉树中结点的值(一个字符),’#’字符表示空树,
// 构造二叉链表表示的二叉树T。
char ch;
scanf("%c",&ch);
if (ch==’#’) T = NULL;
else {
if (!(T = (BiTNode *)malloc(sizeof(BiTNode)))) return ERROR;
________________________ // 生成根结点
_______________________ // 构造左子树
_________________________ // 构造右子树
}
return OK;
} // CreateBiTree

Status PreOrderTraverse( BiTree T) {
// 前序遍历二叉树T的递归算法
//补全代码,可用多个语句

} // PreOrderTraverse

Status InOrderTraverse( BiTree T) {
// 中序遍历二叉树T的递归算法
//补全代码,可用多个语句

} // InOrderTraverse

Status PostOrderTraverse( BiTree T) {
// 后序遍历二叉树T的递归算法
//补全代码,可用多个语句

} // PostOrderTraverse

int main() //主函数
{
//补充代码
}//main

输入格式
第一行:输入一棵二叉树的先序遍历序列

输出格式
第一行:二叉树的先序遍历序列
第二行:二叉树的中序遍历序列
第三行:二叉树的后序遍历序列

输入样例
AB##C##

输出样例
ABC
BAC
BCA

解题思路

直接照着写就行。。

AC代码

#include "stdio.h"
#include "malloc.h"
#include <iostream>
#define TRUE 1
#define FALSE 0
#define OK  1
#define ERROR  0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int  Status;

typedef char  ElemType;
typedef struct BiTNode {
    ElemType data;
    struct BiTNode *lchild,*rchild;//左右孩子指针
} BiTNode,*BiTree;
using namespace std;

Status CreateBiTree(BiTree &T) {  // 算法6.4
    // 按先序次序输入二叉树中结点的值(一个字符),’#’字符表示空树,
    // 构造二叉链表表示的二叉树T。
    char ch;
    cin>>ch;
    if (ch=='#')
        T = NULL;
    else {
        if (!(T = (BiTNode *)malloc(sizeof(BiTNode))))
            return ERROR;
        T->data=ch; // 生成根结点
        CreateBiTree(T->lchild);// 构造左子树
        CreateBiTree(T->rchild); // 构造右子树
    }
    return OK;
} // CreateBiTree


Status PreOrderTraverse( BiTree T) {
    // 前序遍历二叉树T的递归算法
    /*根左右*/
    if(T==NULL)
    {
        return OK;
    }
    cout<<T->data;
    PreOrderTraverse(T->lchild);
    PreOrderTraverse(T->rchild);
} // PreOrderTraverse

Status InOrderTraverse( BiTree T) {
    // 中序遍历二叉树T的递归算法
    if(T==NULL)
    {
        return OK;
    }
    InOrderTraverse(T->lchild);
    cout<<T->data;
    InOrderTraverse(T->rchild);
} // InOrderTraverse

Status PostOrderTraverse( BiTree T) {
    // 后序遍历二叉树T的递归算法
    if(T==NULL)
    {
        return OK;
    }
    PostOrderTraverse(T->lchild);
    PostOrderTraverse(T->rchild);
    cout<<T->data;
} // PostOrderTraverse

int main()   //主函数
{
    BiTree T;
    CreateBiTree(T);
    PreOrderTraverse(T);
    cout<<'\n';
    InOrderTraverse(T);
    cout<<'\n';
    PostOrderTraverse(T);
    cout<<'\n';
    return 0;
}//main

题2:17121 求二叉树各种节点数

题目描述

Description
构造二叉链表表示的二叉树:按先序次序输入二叉树中结点的值(一个字符),’#'字符表示空树,构造二叉链表表示的二叉树T,并求此二叉树中度为2的节点总数,度为1的节点总数,度为0的节点总数

#include “stdio.h”
#include “malloc.h”
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;

typedef char ElemType;
typedef struct BiTNode{
ElemType data;
struct BiTNode *lchild,*rchild;//左右孩子指针
} BiTNode,*BiTree;

Status CreateBiTree(BiTree &T) { // 算法6.4
// 按先序次序输入二叉树中结点的值(一个字符),’#’字符表示空树,
// 构造二叉链表表示的二叉树T。
char ch;
scanf("%c",&ch);
if (ch==’#’) T = NULL;
else {
if (!(T = (BiTNode *)malloc(sizeof(BiTNode)))) return ERROR;
________________________ // 生成根结点
_______________________ // 构造左子树
_________________________ // 构造右子树
}
return OK;
} // CreateBiTree

int main() //主函数
{
//补充代码
}//main

输入格式
第一行输入先序次序二叉树中结点

输出格式
第一行输出度为2的节点数
第二行输出度为1的节点数
第三行输出度为0的节点数

输入样例
ABC###D##

输出样例
1
1
2

解题思路

解读术语:
节点的度:节点拥有的子树称为节点的度,即由当前节点可以引出多少棵树?
树的度:树的度值得是树内各节点度的最大值
叶子:度为0的节点称为叶子或者终端节点
树的深度:树中节点的最大层次称为树的深度或者高度
记住以下几个重要结论:
(1)在二叉树的第i层上至多有2的i-1次方个节点
(2)深度为k的二叉树至多由2的k-1次方个节点
(3)树中各度节点的关系
对任何一棵二叉树,如果其终端节点为n0,度为2的节点树为n2,那么n0=n2-1;
证明:设n1为二叉树T中度为1的节点数,因为二叉树中所有节点的度均小于等于2,所以其节点总数为n=n0+n1+n2;(因为总共也就三种情况)
再看二叉树的分支,除了根节点以外,其余节点都有一个分支进入,设B为分支总数,则n=B+1(包括根节点),由于这些分支是由度为1或者2的节点射出的,所以又有B=n1+2*n2(也就是说度1,只发出一条分支,度2,发出两条分支)
那么也就是n=n1+2*n2+1,,综上解得n0=n2-1

AC代码

#include "stdio.h"
#include "malloc.h"
#include <iostream>
#define TRUE 1
#define FALSE 0
#define OK  1
#define ERROR  0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int  Status;
int n=0,n1=0,n2=0,n0=0;
typedef char  ElemType;
typedef struct BiTNode{
  ElemType data;
  struct BiTNode *lchild,*rchild;//左右孩子指针
} BiTNode,*BiTree;
using namespace std;

Status CreateBiTree(BiTree &T) {  // 算法6.4
  // 按先序次序输入二叉树中结点的值(一个字符),’#’字符表示空树,
  // 构造二叉链表表示的二叉树T。
  char ch;
  cin>>ch;
  if (ch=='#') T = NULL;
  else {
    if (!(T = (BiTNode *)malloc(sizeof(BiTNode)))) return ERROR;
    T->data=ch;n++; // 生成根结点,记数
    CreateBiTree(T->lchild);   // 构造左子树
    CreateBiTree(T->rchild);  // 构造右子树
  }
  return OK;
} // CreateBiTree

/*还需要获取一个0度节点*/

Status PreOrderTraverse( BiTree T) {
    // 前序遍历二叉树T的递归算法
    /*根左右*/
    if(T==NULL)
    {
        return OK;
    }
    if(T->lchild==NULL && T->rchild==NULL)
    {
        n0++;
        return OK;
    }
    PreOrderTraverse(T->lchild);
    PreOrderTraverse(T->rchild);
} // PreOrderTraverse

int main()   //主函数
{
    BiTree T;
    CreateBiTree(T);
    PreOrderTraverse(T);
    n2=n0-1;
    n1=n-2*n2-1;
    cout<<n2<<'\n';
    cout<<n1<<'\n';
    cout<<n0<<'\n';
}//main

题3:18924 二叉树的宽度

题目描述

Description
二叉树的宽度指的是具有节点数目最多的那一层的节点个数。
1
/
2 3
/
4
答案为2, 第二层节点数最多,为2个节点。

输入格式
共n行。
第一行一个整数n,表示有n个结点,编号为1至n,结点1为树根。(1<=n<=50)
第二行至第n行,每行有两个整数x和y,表示在二叉树中x为y的父节点。x第一次出现时y为左孩子

输出格式
输出二叉树的宽度。

输入样例
5
1 2
1 3
2 4
2 5

输出样例
2

解题思路

本题要求的是每一层上最多的节点数,可以考虑先建树,再搜索,搜索由于是搜索同一层的,这一点是有着广度优先搜索的特点,所以采用BFS的方案。

AC代码

#include <iostream>
#include <algorithm>
using namespace std;
const int M=1e5+5;
const int INF=0x3f3f3f3f;
struct node
{
    int lch,rch;
};

struct node q[M];

int main()
{
    ios::sync_with_stdio(false);
    int n,x,y;cin>>n;
    /*初始化数组*/
    for(int i=0;i<n;i++)
    {
        q[i].lch=q[i].rch=0;
    }
    for(int i=1;i<n;i++)
    {
        cin>>x>>y;
        if(q[x].lch==0)
        {
            q[x].lch=y;
        }
        else
        {
            q[x].rch=y;
        }
    }
    /*建树*/
    /*队列初始化*/
    int a[M];
    int head=0,tail=0,ans=-INF;int len=0;
    a[tail]=1;
    tail++;
    while(head<tail)
    {
        len=tail-head;/*代表当前层的宽度,方便我们扩展节点*/
        ans=max(ans,len);
        for(int i=1;i<=len;i++)
        {
            int e=a[head++];/*一个节点只能扩展一次*/
            if(q[e].lch!=0)
            {
                a[tail++]=q[e].lch;
            }
            if(q[e].rch!=0)
            {
                a[tail++]=q[e].rch;
            }
        }
    }
    cout<<ans<<'\n';
    return 0;
}

题4:18923 二叉树的直径

题目描述

Description
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
1
/
2 3
/ \
4 5
答案为3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。

输入格式
共n行。
第一行一个整数n,表示有n个结点,编号为1至n。
第二行至第n行,每行有两个整数x和y,表示在二叉树中x为y的父节点。x第一次出现时y为左孩子

输出格式
输出二叉树的直径。

输入样例
5
1 2
1 3
2 4
2 5

输出样例
3

解题思路

本题实际上是求各个节点的情况,也就是求一个最长路径的问题,所以想到采用深搜的方法进行搜索长度,因此本题采用的基本思路是DFS

AC代码

#include <iostream>
#include <cstring>

using namespace std;

const int M=1e6+5;
const int INF=0x3f3f3f;
int book[M];
int leave[M];/*标记数组,叶子数组*/
int Max=-INF,n;

struct data
{
    int lch,rch,p;
};
struct data a[M];

void dfs(int cur,int step)
{
    int flag=0;
    for(int i=1;i<=n;i++)
    {
        if(book[i]==0)
        {
            flag=1;
            break;
        }
    }
    if(flag==0)
    {
        if(step>Max)
        {
            Max=step;
        }
        return ;
    }
    int c[3]={0};
    c[0]=a[cur].lch;c[1]=a[cur].rch;c[2]=a[cur].p;
    for(int i=0;i<3;i++)/*枚举搜索方向*/
    {
        if(c[i]!=0 && book[c[i]]==0)
        {
            book[c[i]]=1;
            dfs(c[i],step+1);
        }
    }
    return ;
}

int main()
{
    ios::sync_with_stdio(false);
    memset(a,0,sizeof(a));
    cin>>n;
    for(int i=1;i<n;i++)
    {
        int x,y;cin>>x>>y;
        if(a[x].lch==0)
        {
            a[x].lch=y;
            a[y].p=x;
        }
        else if(a[x].rch==0)
        {
            a[x].rch=y;
            a[y].p=x;
        }
    }
    /*将树图建好*/
    /*寻找所有的叶子节点*/
    int idx=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i].lch==0 && a[i].rch==0)/*如果是叶子节点,加入叶子数组*/
        {
            leave[idx++]=i;
        }/*记录下节点的编号*/
    }
    for(int i=0;i<idx;i++)/*以所有的叶子节点为起点,dfs答案*/
    {
        memset(book,0,sizeof(book));
        book[leave[i]]=1;
        dfs(leave[i],0);
    }
    cout<<Max;
}

题5:18724 二叉树的遍历运算

题目描述

Description
二叉树的三种遍历都可以通过递归实现。
如果我们知道一棵二叉树的先序和中序序列,可以用递归的方法求后序遍历序列。

输入格式
两行,第一行一个字符串,表示树的先序遍历,第二行一个字符串,表示树的中序遍历。树的结点一律用小写字母表示。

输出格式
一个字符串,树的后序序列。

输入样例
abcde
bcade

输出样例
cbeda

作者 30002692

解题思路

首先记住两点:①先序遍历可以确定根节点②中序遍历可以确定左右子树。
通过这两点,为我们的编程提供了思路:首先先序遍历可以确定根节点的位置,确定下来之后,在中序遍历数组中定位根节点的位置,找到根节点之后,通过计算当前pos(用来记录中序数组中根节点的位置)-len,再用ZR-根节点的位置,就确定下来了左右子树的区间,然后同样的方法,传递参数下去,继续递归遍历,遍历的过程中就可以把树建好,直到遇到递归出口,那么递归出口是什么呢?
通过我们的演算可以知道,当不存在左子树和右子树的情况的时候,都会出现左递归起点大于右递归起点,那么一旦出现这种情况的时候,就可以断言,此时已经不能够再划分出左右子树,递归出口,就是这个条件。转化为代码即可。那么在我们代码中,会不会出现找不到根节点情况呢?那么这时候我显然可以得知,这种情况是不能划分出子树的一个特征,于是我们提前剪枝即可。
那么现在总结公式:
递归左子树起点(先序数组):先序数组起点+1,递归左子树终点:先序数组起点+len
递归左子树起点(中序数组):中序数组起点,递归左子树终点:找到的pos-1
递归右子树起点(先序数组) :先序数组起点+len+1,递归右子树终点:先序数组终点
递归右子树起点(中序数组):pos+1,递归右子树终点中序数组终点

AC代码

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef char  ElemType;
typedef struct BiTNode{
  ElemType data;
  struct BiTNode *lchild,*rchild;//左右孩子指针
} BiTNode,*BiTree;

const int M=1e5+5;
char x[M],z[M];

void CT(BiTree &T,int XL,int XR,int ZL,int ZR)
{
    if(XL>XR || ZL>ZR)
    {
        T=NULL;
        return ;
    }
    int pos=0;
    T=new BiTNode;T->data=x[XL];
    T->data=x[XL];
    for(int i=ZL;i<=ZR;i++)
    {
        if(z[i]==x[XL])
        {
            pos=i;
            break;
        }
    }
    int len=pos-ZL;
    CT(T->lchild,XL+1,XL+len,ZL,pos-1);
    CT(T->rchild,XL+len+1,XR,pos+1,ZR);
}

void HX(BiTree T)
{
    if(T==NULL)
    {
        return ;
    }
    HX(T->lchild);
    HX(T->rchild);
    cout<<T->data;
}

int main()
{
    BiTree T;
    cin>>x>>z;
    int n=strlen(x);
    CT(T,0,n-1,0,n-1);
    HX(T);
    return 0;
}

题6:8609 哈夫曼树

题目描述

Description 利用静态链表建立赫夫曼树,建树过程中要求左子树权值小于右子树权值,求各结点的编码。要求:叶子结点的个数n及结点值由键盘录入。本题给出程序代码,要求修改以满足测试要求.
输入格式
第一行:权值个数
第二行:输入n个权值,用空格分隔

输出格式
输出n行
每行表示各权值对应的哈夫曼编码

输入样例
8
5 29 7 8 14 23 3 11

输出样例
0001
10
1110
1111
110
01
0000
001

作者 yqm

Version: 0

AC代码

#include "stdio.h"
#include "malloc.h"
#include "string.h"
typedef struct{
   unsigned int weight;
   unsigned int parent,lchild,rchild;
}HTNode,*HuffmanTree;
typedef char **HuffmanCode;
void   Select(HuffmanTree &HT, int n, int &s1, int &s2)
//在HT[1..n]中选择parent为0且weight最小的两个结点,
// 其序号分别为s1和s2。
{
    s1=-1,s2=-1;
    for(int i=1;i<=n;i++)
    {
        if(HT[i].parent==0)
        {
            if(s1==-1)
            {
                s1=i;
            }
            else if(HT[i].weight<HT[s1].weight)
            {
                s2=s1;
                s1=i;
            }
            else if(s2==-1)
            {
                s2=i;
            }
            else if(HT[i].weight<HT[s2].weight)
            {
                s2=i;
            }
        }
    }
  // 并求出n个字符的哈夫曼编码HC
}
void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n)
{
  int i, m, s1, s2, start;
  char *cd;
  unsigned int c, f;
  if (n<=1) return;
  m = 2 * n - 1;
  HT = (HuffmanTree)malloc((m+1) * sizeof(HTNode));  // 0号单元未用
  for (i=1; i<=n; i++) { //初始化
    HT[i].weight=w[i-1];
    HT[i].parent=0;
    HT[i].lchild=0;
    HT[i].rchild=0;
  }
  for (i=n+1; i<=m; i++) { //初始化
    HT[i].weight=0;
    HT[i].parent=0;
    HT[i].lchild=0;
    HT[i].rchild=0;
  }
  for (i=n+1; i<=m; i++) {  // 建哈夫曼树
    // 在HT[1..i-1]中选择parent为0且weight最小的两个结点,
    // 其序号分别为s1和s2。
    Select(HT, i-1, s1, s2);
    HT[s1].parent = i;  HT[s2].parent = i;
    HT[i].lchild = s1;  HT[i].rchild = s2;
    HT[i].weight = HT[s1].weight + HT[s2].weight;
  }
   //--- 从叶子到根逆向求每个字符的哈夫曼编码 ---
  cd = (char *)malloc(n*sizeof(char));    // 分配求编码的工作空间
  cd[n-1] = '\0';                         // 编码结束符。
  for (i=1; i<=n; ++i) {                  // 逐个字符求哈夫曼编码
    start = n-1;                          // 编码结束符位置
    for (c=i, f=HT[i].parent; f!=0; c=f, f=HT[f].parent)
      // 从叶子到根逆向求编码
      if (HT[f].lchild==c) cd[--start] = '0';
      else cd[--start] = '1';
    HC[i] = (char *)malloc((n-start)*sizeof(char));
         // 为第i个字符编码分配空间
    strcpy(HC[i], &cd[start]);    // 从cd复制编码(串)到HC

  }
  free(cd);   //释放工作空间
} //HuffmanCoding

int main()
{
   int i,n;
   int *w;
   HuffmanTree HT;
   HuffmanCode HC;
   scanf("%d",&n);  //权值个数
   w=(int *)malloc(n*sizeof(int));
   for ( i=0;i<n;i++)  //录入权值
	 scanf("%d",&w[i]);
   HC=(char **)malloc((n+1)*sizeof(char*)); //0空间未用
   HT=(HuffmanTree)malloc((2*n+1+1)*sizeof(HTNode));//0空间未用
   HuffmanCoding(HT, HC, w, n);
   for (i = 1; i<n+1; i++){
	 puts(HC[i]);  //输出哈夫曼编码
	 free(HC[i]);  //释放空间
   }
   free(HC);
   free(HT);
}//main

  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值