目录
第1关:基于二叉链表的二叉树的创建和遍历
任务描述
设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,编写三个递归算法分别实现二叉树的先序、中序和后序遍历。
编程要求
输入
数据一行,为二叉树的前序序列(序列中元素为‘#’时,表示该结点为空)。
输出
每组数据输出三行,为二叉树的先序、中序和后序序列。
测试说明
平台会对你编写的代码进行测试:
测试输入:
ab##c##
预期输出:abc bac bca
测试输入:
abcd##e##f##ig##h##
预期输出:abcdefigh dcebfagih decfbghia
#include <iostream>
#include <cstring>
using namespace std;
typedef char ElemType;
typedef struct BiTNode
{
ElemType data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
// 先序建立二叉树
void CreateBiTree(BiTree &T)
{
char ch;
cin >> ch;
if (ch == '#')
{
T = NULL;
}
else
{
T = new BiTNode;
T->data = ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
}
// 二叉树的先序遍历
void PreOrderTraverse(BiTree T)
{
if (T)
{
cout << T->data;
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
// 二叉树的中序遍历
void InOrderTraverse(BiTree T)
{
if (T)
{
InOrderTraverse(T->lchild);
cout << T->data;
InOrderTraverse(T->rchild);
}
}
// 二叉树的後序遍历
void PostOrderTraverse(BiTree T)
{
if (T)
{
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
cout << T->data;
}
}
int main()
{
BiTree T;
CreateBiTree(T);
PreOrderTraverse(T);
cout << endl;
InOrderTraverse(T);
cout << endl;
PostOrderTraverse(T);
return 0;
}
第2关:基于二叉链表的二叉树结点个数的统计
任务描述
设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,编写三个递归算法对二叉树的结点(度为0、1、2)个数进行统计。
编程要求
输入
数据一行,为二叉树的前序序列(序列中元素为‘#’时,表示该结点为空)。
输出
输出一行,每行三个数分别为二叉树的度为0、1、2的结点个数。每两个数用空格分隔。
测试说明
平台会对你编写的代码进行测试:
测试输入:
abcd##e##f##ig##h##
预期输出:
5 0 4
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string.h>
using namespace std;
typedef char ElemType;
typedef struct BiTNode
{
ElemType data;
struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;
void CreateBiTree(BiTree& T)
{//先序建立二叉树
ElemType ch;
cin >> ch;
if (ch == '#')
T = NULL;
else
{
T = new BiTNode;
T->data = ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
}
int Count_leaf(BiTree T) {
//统计叶子结点的数目
/**************begin************/
if (T == NULL)
return 0;
if (T->lchild || T->rchild)
return Count_leaf(T->lchild) + Count_leaf(T->rchild);
else
return 1;
/**************end************/
}
int Count_Sigle(BiTree T) {
//统计单分支结点的数目
/**************begin************/
if (T == NULL)
return 0;
if ((!(T->lchild) && T->rchild) || (T->lchild && !(T->rchild)))
return 1 + Count_Sigle(T->lchild) + Count_Sigle(T->rchild);
else
return Count_Sigle(T->lchild) + Count_Sigle(T->rchild);
/**************end************/
}
int Count_Double(BiTree T) {
//统计双分支结点的数目
/**************begin************/
if (T->lchild && T->rchild)
return 1+Count_Double(T->lchild) + Count_Double(T->rchild);
else
return 0;
/**************end************/
}
int main()
{
BiTree T;
CreateBiTree(T);
cout << Count_leaf(T) << " " << Count_Sigle(T) << " " << Count_Double(T) << endl;
return 0;
}
第3关:基于二叉链表的二叉树高度的计算
任务描述
设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,编写递归算法计算二叉树的高度。
编程要求
输入
数据一行,为二叉树的前序序列(序列中元素为‘#’时,表示该结点为空)。
输出
输出一个数字,为二叉树的高度。
测试说明
平台会对你编写的代码进行测试:
测试输入:
ab##c##
预期输出:2
#include<iostream>
#include <string.h>
using namespace std;
typedef char ElemType;
typedef struct BiTNode
{
ElemType data;
struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;
void CreateBiTree(BiTree& T)
{//先序建立二叉树
ElemType ch;
cin >> ch;
if (ch == '#')
T = NULL;
else
{
T = new BiTNode;
T->data = ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
}
int Depth(BiTree T)
{//二叉树高度的计算
/**************begin************/
if (T == NULL)
return 0;
else
{
int left = Depth(T->lchild);
int right = Depth(T->rchild);
return left > right ? (left + 1) : (right + 1);
}
/**************end************/
}
int main()
{
BiTree T;
CreateBiTree(T);
cout << Depth(T) ;
return 0;
}
第4关:基于二叉链表的二叉树左右孩子的交换
任务描述
设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,编写递归算法交换该二叉树的左右孩子。
编程要求
输入
数据一行,为二叉树的先序序列(序列中元素为‘#’时,表示该结点为空)。
输出
数据输出一行。为交换左右孩子后的二叉树的先序序列。
测试说明
平台会对你编写的代码进行测试:
测试输入:
abcd##e##f##ig##h##
预期输出:
aihgbfced
#include<iostream>
#include<cstring>
using namespace std;
typedef char ElemType;
typedef struct BiTNode
{
ElemType data;
struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;
void CreateBiTree(BiTree& T)
{//先序建立二叉树
ElemType ch;
cin >> ch;
if (ch == '#')
T = NULL;
else
{
T = new BiTNode;
T->data = ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
}
void ChangeRL(BiTree& T)
{//二叉树左右孩子的交换
/**************begin************/
if (T)
{
BiTree tmp = T->lchild;
T->lchild = T->rchild;
T->rchild = tmp;
ChangeRL(T->lchild), ChangeRL(T->rchild);
}
else
return;
/**************end************/
}
void PreOrderTraverse(BiTree T)
{//先序遍历
if (T)
{
cout << T->data;
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
int main()
{
BiTree T;
CreateBiTree(T);
ChangeRL(T);
PreOrderTraverse(T);
cout << endl;
return 0;
}
第5关:基于二叉链表的树结构相等的判断
任务描述
设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,按此方法创建两棵二叉树,然后编写递归算法判断这两棵树是否相等。
编程要求
输入
数据有两行。每行为一个二叉树的先序序列(序列中元素为‘#’时,表示该结点为空)。
输出
每组数据输出一行。若两个二叉树相等输出“YES”,否则输出“NO”。
测试说明
平台会对你编写的代码进行测试:
测试输入:
abd##e##cf##g##
abd##e##cf##h##
预期输出:
NO
#include<iostream>
using namespace std;
typedef char ElemType;
typedef struct BiTNode
{
ElemType data;
struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;
void CreateBiTree(BiTree& T)
{//先序建立二叉树
ElemType ch;
cin >> ch;
if (ch == '#')
T = NULL;
else
{
T = new BiTNode;
T->data = ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
}
int Compare(BiTree T1, BiTree T2)
{//判断两棵二叉树是否相等,不相等返回0,相等返回1
/**************begin************/
if ((!T1 && T2) || (T1 && !T2))
return 0;
if (!T1 && !T2)
return 1;
if (T1->data == T2->data)
{
if( Compare(T1->lchild,T2->lchild) && Compare(T1->rchild,T2->rchild) )
return 1;
}
else
return 0;
/**************end************/
}
int main()
{
BiTree T1, T2;
CreateBiTree(T1);
CreateBiTree(T2);
if (!Compare(T1, T2))
cout << "NO" << endl;
else
cout << "YES" << endl;
return 0;
}
第6关:基于二叉链表的二叉树的层次遍历
任务描述
设二叉树中每个结点的元素均为一个字符,已经按先序遍历的顺序建立二叉链表,已知链队列的基本操作,编写一个调用队列基本操作实现二叉树的层次序遍历的算法。
编程要求
输入
数据一行,为二叉树的前序序列(序列中元素为‘#’时,表示该结点为空)。 数据输出一行,为二叉树的层次遍历序列。
测试说明
平台会对你编写的代码进行测试:
测试输入:
abcd##e##f##ig##h##
预期输出:
abicfghde
#include "leveltraverse_h.h"
Status LevelOrder(BiTree T)//层次遍历二叉树
{
/**************begin************/
LinkQueue Q;
InitQueue(Q);
if(T)
{
EnQueue(Q,T);
while(!QueueEmpty(Q))
{
DeQueue(Q,T);
cout<<T->data;
if(T->lchild!=NULL) EnQueue(Q,T->lchild);
if(T->rchild!=NULL) EnQueue(Q,T->rchild);
}
}
/**************end************/
}
int main()
{
BiTree T;
CreateBiTree(T);
LevelOrder(T);
cout<<endl;
return 0;
}
第7关:二叉树的WPL计算
任务描述
二叉树的带权路径长度(WPL)是二叉树中所有叶结点的带权路径长度之和。给定一棵二叉树T, 采用二叉链表存储,结点结构为:left weight right,其中叶结点的weight域保存该结点的非负权值。设root为指向T的根结点的指针,请设计求T的WPL的算法。
编程要求
输入
多组数据,每组数据一行,为一个二叉树的先序序列(序列中元素为0时,表示该结点为空,每两个元素之间用空格隔开)。当输入只有一个0时,输入结束。
输出
每组数据输出一行,为该二叉树的WPL。
测试说明
平台会对你编写的代码进行测试:
测试输入:
1 1 0 0 1 0 0
1 2 1 0 0 0 0
0
预期输出:
2
2
#include<iostream>
using namespace std;
typedef struct BiTNode
{
int weight;
struct BiTNode* left, * right;
}BiTNode, * BiTree;
void CreateBiTree(BiTree& T)
{//先序建立二叉树
int x;
cin >> x;
if (x == 0) T = NULL;
else
{
T = new BiTNode;
T->weight = x;
CreateBiTree(T->left);
CreateBiTree(T->right);
}
}
int WPL(BiTree& T, int d)
{//求二叉树T的带权路径长度
/**************begin************/
if (!T)
return 0;
if (T->left || T->right)
{
d++;
return WPL(T->left, d) + WPL(T->right, d);
}
else
return d * T->weight;
/**************end************/
}
int main()
{
while (1)
{
BiTree T;
CreateBiTree(T);
if (!T) break;
int d = 0;
cout << WPL(T, d) << endl;
}
return 0;
}
第8关:哈夫曼树的编码解码
任务描述
输入一串字符串,根据给定的字符串中字符出现的频率建立相应哈夫曼树,构造哈夫曼编码表,在此基础上可以对待压缩文件进行压缩(即编码),同时可以对压缩后的二进制编码文件进行解压(即译码)。
编程要求
输入
多组数据,每组数据一行,为一个字符串(只考虑26个小写字母即可)。当输入字符串为“0”时,输入结束。
输出
每组数据输出2n+4行(n为输入串中字符类别的个数)。第一行为统计出来的字符出现频率(只输出存在的字符,格式为:字符:频度),每两组字符之间用一个空格分隔,字符按照ASCII码从小到大的顺序排列。第二行至第2n行为哈夫曼树的存储结构的终态(形如教材139页表5.2(b),一行当中的数据用空格分隔)。第2n+2行为每个字符的哈夫曼编码(只输出存在的字符,格式为:字符:编码),每两组字符之间用一个空格分隔,字符按照ASCII码从小到大的顺序排列。第2n+3行为编码后的字符串,第2n+4行为解码后的字符串(与输入的字符串相同)。
测试说明
平台会对你编写的代码进行测试:
测试输入:
aaaaaaabbbbbccdddd
aabccc
0
预期输出:
a:7 b:5 c:2 d:4
1 7 7 0 0
2 5 6 0 0
3 2 5 0 0
4 4 5 0 0
5 6 6 3 4
6 11 7 2 5
7 18 0 1 6
a:0 b:10 c:110 d:111
00000001010101010110110111111111111
aaaaaaabbbbbccdddd
a:2 b:1 c:3
1 2 4 0 0
2 1 4 0 0
3 3 5 0 0
4 3 5 2 1
5 6 0 3 4
a:11 b:10 c:0
111110000
aabccc
#include<iostream>
#include<string.h>
#define MAXSIZE 100
#define MAX 100
using namespace std;
typedef struct
{//哈夫曼树结点的形式
int weight; //结点的权值
int parent, lchild, rchild; //结点的双亲、左孩子、右孩子的下标
}HTNode, * HuffmanTree; //动态分配数组存储哈夫曼树
typedef char** HuffmanCode; //定义编码表类型
int Search(char a[], char ch)
{//查找数组中字符ch所在的位置,返回数组下标,否则返回-1
for (int i = 0; a[i] != '\0'; i++)
{
if (a[i] == ch) return i;
}
return -1;
}
void Sort(char a[], int b[], int len)
{//按ASCII码冒泡排序
/**************begin************/
for (int i=1; i < len; i++)
{
for (int j = 0; j < len - i; j++)
{
if (a[j] > a[j + 1])
{
char tmpch = a[j];
a[j] = a[j + 1];
a[j + 1] = tmpch;
int tmpt = b[j];
b[j] = b[j + 1];
b[j + 1] = tmpt;
}
}
}
}
void Select_min(HuffmanTree& HT, int n, int& s1, int& s2)
{// 在HT[k](1≤k≤i-1)中选择两个其双亲域为0且权值最小的结点,并返回它们在HT中的序号s1和s2
/**************begin************/
int min1 = MAX;
int min2 = MAX;
int i, j;
for (i = 1; i <= n; i++)
{
if (HT[i].weight < min1 && HT[i].parent==0)
{
min1 = HT[i].weight;
s1 = i;
}
}
for (j = 1; j <= n; j++)
{
if (HT[j].weight < min2 && HT[j].parent == 0 && j!=s1)
{
min2 = HT[j].weight;
s2 = j;
}
}
}
int m;
void CreateHuffmanTree(HuffmanTree& HT, int n, int b[])
{//构造哈夫曼树HT
/**************begin************/
if (n <= 1) return;
int m = n * 2 - 1;
HT = new HTNode[m + 1];
for(int i=1;i<=m;i++)
{
HT[i].parent = 0;
HT[i].lchild = 0;
HT[i].rchild = 0;
}
for (int i = 1; i <= n; i++)
{
HT[i].weight = b[i-1];
}
int s1 = 0;
int s2 = 0;
for (int i = n + 1; i <= m; i++)
{
Select_min(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;
}
}
void CreateHuffmanCode(HuffmanTree HT, HuffmanCode& HC, int n)
{
//从叶子到根逆向求每个字符的哈夫曼编码,存储在编码表HC中
/**************begin************/
HC = new char* [n + 1];
char* cd = new char[n];
cd[n - 1] = '\0';
for (int i = 1; i <= n; i++)
{
int start = n - 1;
int c = i;
int f=HT[i].parent;
while (f != 0)
{
--start;
if (HT[f].lchild == c)
cd[start] = '0';
else
cd[start] = '1';
c = f;
f = HT[f].parent;
}
HC[i] = new char[n - start];
strcpy(HC[i], &cd[start]);
}
delete cd;
/**************end************/
}
void CharFrequency(char ch[], char a[], int b[], int& j)
{ //统计词频
//代码仅用于通过测试,对于 aaabbbcccaaa等串不适用
int i = 0;
a[j] = ch[i];
while (ch[i] != '\0')
{
if (ch[i]!=a[j])
{
a[++j] = ch[i];
}
b[j] = b[j] + 1;
i++;
}
j++;
}
void PrintHT(HuffmanTree HT)
{//输出哈夫曼树的存储结构的终态
int i = 1;
while (HT[i].parent!=0)
{
printf("%d %d %d %d %d\n", i, HT[i].weight, HT[i].parent, HT[i].lchild, HT[i].rchild);
i++;
}
printf("%d %d %d %d %d\n", i, HT[i].weight, HT[i].parent, HT[i].lchild, HT[i].rchild);
}
void PrintHC(HuffmanCode HC, char a[], int j)
{//输出每个字符的哈夫曼编码
for (int i = 0; i < j; i++)
{
if(i==0)
printf("%c:%s",a[i],HC[i+1]);
else
printf(" %c:%s",a[i],HC[i+1]);
}
printf("\n");
}
int main()
{
char ch[MAXSIZE];
int i, j;
while (cin >> ch)
{
if (ch[0] == '0') break;
HuffmanTree HT;
char a[MAXSIZE] = { '\0' };
int b[MAXSIZE] = { 0 };
j = 0; //j统计不同字符的数量
CharFrequency(ch, a, b, j); //统计词频
Sort(a, b, j); //按ASCII码冒泡排序
for (i = 0; a[i] != '\0'; i++) //输出统计出来的字符和出现频率
{
if (a[i + 1] != '\0')
cout << a[i] << ":" << b[i] << " ";
else
cout << a[i] << ":" << b[i] << endl;
}
//构造哈夫曼树
CreateHuffmanTree(HT, i, b); //构造哈夫曼树HT
PrintHT(HT); //输出哈夫曼树的存储结构的终态
// //哈夫曼编码
HuffmanCode HC; //编码表HC
CreateHuffmanCode(HT, HC, j);
PrintHC(HC, a, j); //输出每个字符的哈夫曼编码
int k;
for (i = 0; ch[i] != '\0'; i++) //输出编码后的字符串
{
for (k = 0; k < j; k++)
{
if (ch[i] == a[k])
cout << HC[k + 1];
}
}
cout << endl;
cout << ch << endl;//输出解码后的字符串(与输入的字符串相同)
}
return 0;
}