题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