问题 A: DS二叉树——Huffman编码与解码(不含代码框架)
题目描述
1、问题描述
给定n个字符及其对应的权值,构造Huffman树,并进行huffman编码和译(解)码。
构造Huffman树时,要求左子树根的权值小于、等于右子树根的权值。
进行Huffman编码时,假定Huffman树的左分支上编码为‘0’,右分支上编码为‘1’。
2、算法
构造Huffman树算法:
⑴ 根据给定的n个权值(w1, w2, …, wn)构成n棵二叉树的集合F={T1, T2, …, Tn},其中每棵二叉树Ti中只有一个权值为wi的根结点。
⑵ 在F中选取两棵根结点的权值最小的树,作为左、右子树构造一棵新的二叉树,且置其根结点的权值为其左、右子树权值之和。
⑶ 在F中删除这两棵树,同时将新得到的二叉树加入F中。
(4) 重复⑵, ⑶,直到F只含一棵树为止。
3、Huffman编码算法:
⑴ 从Huffman树的每一个叶子结点开始。
⑵ 依次沿结点到根的路径,判断该结点是父亲结点的左孩子还是右孩子,如果是左孩子则得到编码‘0’,否则得到编码‘1’,先得到的编码放在后面。
⑶ 直到到达根结点,编码序列即为该叶子结点对应的Huffman编码。
4、Huffman译(解)码算法:
⑴ 指针指向Huffman树的根结点,取第一个Huffman码。
⑵ 如果Huffman码为‘0’,将指针指向当前结点的左子树的根结点;如果Huffman码为‘1’,将指针指向当前结点的右子树的根结点。
⑶ 如果指针指向的当前结点为叶子结点,则输出叶子结点对应的字符;否则,取下一个Huffman码,并返回⑵。
⑷ 如果Huffman码序列未结束,则返回⑴继续译码。
输入
第一行测试次数
第2行:第一组测试数据的字符个数n,后跟n个字符
第3行:第一组测试数据的字符权重
待编码的字符串s1
编码串s2
其它组测试数据类推
输出
第一行~第n行,第一组测试数据各字符编码值
第n+1行,串s1的编码值
第n+2行,串s2的解码值,若解码不成功,输出error!
其它组测试数据类推
样例输入
2
5 A B C D E
15 4 4 3 2
ABDEC
00000101100
4 A B C D
7 5 2 4
ABAD
1110110
样例输出
A :1
B :010
C :011
D :001
E :000
1010001000011
error!
A :0
B :10
C :110
D :111
0100111
DAC
AC代码
#include<iostream>
#include<algorithm>
using namespace std;
struct Ha_TNode {
int parent, left, right, weight;
string code;
char data;
Ha_TNode() { parent = 0; left = 0; right = 0; }
};
class HTree {
Ha_TNode* root;
int num;
public:
HTree(int n = 0) {
num = n;
root = new Ha_TNode[2 * n];
for (int i = 1; i <= n; i++)
cin >> root[i].data;
for (int i = 1; i <= n; i++)
cin >> root[i].weight;
}
void selectMin(int len, int& p1, int& p2) {
int _max , min1, min2;
_max = min1 = min2 = 10000;
p1 = p2 = 0;
for (int i = 1; i < len; i++) {
if (root[i].parent == 0)
if (root[i].weight < min1) {
min2 = min1;
p2 = p1;
min1 = root[i].weight;
p1 = i;
}
else if (root[i].weight < min2) {
min2 = root[i].weight;
p2 = i;
}
}
}
void create_tree() {
int p1 = 0, p2 = 0;
for (int i = num + 1; i < 2 * num; i++) {
selectMin(i, p1, p2);
root[i].left = p1;
root[i].right = p2;
root[p1].parent = root[p2].parent = i;
root[i].weight = root[p1].weight + root[p2].weight;
}
}
void h_code() {
for (int i = 1; i <= num; i++) {
for (int c = i, f = root[i].parent; f != 0; c = f, f = root[f].parent)
if (root[f].left == c)
(root + i)->code = '0' + (root + i)->code;
else
(root + i)->code = '1' + (root + i)->code;
}
}
void Code(string str) {
for (int i = 1; i <= num; i++)
cout << (root + i)->data << " :" << (root + i)->code << endl;
for (int i = 0; i < str.length(); i++)
for (int j = 1; j <= num; j++)
if (str[i] == root[j].data) {
cout << root[j].code;
break;
}
cout << endl;
}
void de_code(string str) {
int Root = 2 * num - 1;
char ch;
int c = Root;
string ans;
for (int i = 0; i < str.length(); i++) {
ch = str[i];
if (ch == '0')
c = root[c].left;
else if (ch == '1')
c = root[c].right;
else
{
cout << "error!" << endl;
break;
}
if ((root[c].left == 0) && (root[c].right == 0)) {
ans += root[c].data;
c = Root;
}
else
ch = '\0';
}
if (ch == '\0')
cout << "error!" << endl;
else
cout << ans << endl;
}
};
int main() {
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
HTree tree(n);
tree.create_tree();
tree.h_code();
string code;
cin >> code;
tree.Code(code);
cin >> code;
tree.de_code(code);
}
return 0;
}
问题 B: DS树–二叉树高度
题目描述
给出一棵二叉树,求它的高度。二叉树的创建采用前面实验的方法。
注意,二叉树的层数是从1开始
输入
第一行输入一个整数t,表示有t个二叉树
第二行起输入每个二叉树的先序遍历结果,空树用字符‘0’表示,连续输入t行
输出
每行输出一个二叉树的高度
样例输入
1
AB0C00D00
样例输出
3
AC代码
#include<bits/stdc++.h>
using namespace std;
struct BTree_node
{
char date;
BTree_node* left, * right;
void set(char c, BTree_node* l = NULL, BTree_node* r = NULL) { date = c; left = l; right = r; }
};
class BTree {
BTree_node* root;
void preorder_tra(BTree_node* node) {
if (!node)
return;
cout << node->date;
preorder_tra(node->left);
preorder_tra(node->right);
}
void inorder_tra(BTree_node* node)
{
if (!node)
return;
inorder_tra(node->left);
cout << node->date;
inorder_tra(node->right);
}
void postorder_tra(BTree_node* node)
{
if (!node)
return;
postorder_tra(node->left);
postorder_tra(node->right);
cout << node->date;
}
void createTree(BTree_node*& node) {
char ch;
cin >> ch;
if ('0' == ch) {
node = NULL;
return;
}
node = new BTree_node;
node->set(ch);
createTree(node->left);
createTree(node->right);
}
void del_tree(BTree_node* node) {
if (!node) {
delete node;
return;
}
del_tree(node->left);
del_tree(node->right);
delete node;
}
int get_depth(BTree_node* node) {
if (node == NULL)
return 0;
int left_depth = get_depth(node->left);
int right_depth = get_depth(node->right);
return 1 + (left_depth > right_depth ? left_depth : right_depth);
}
public:
BTree() { root = NULL; }
void createTree() { createTree(root); }
void preorder_tra() { preorder_tra(root); cout << endl; }
void inorder_tra() { inorder_tra(root); cout << endl; }
void postorder_tra() { postorder_tra(root); cout << endl; }
~BTree() { del_tree(root); }
int get_depth() { return get_depth(root); }
};
int main() {
int n;
cin >> n;
while (n--) {
BTree b;
b.createTree();
cout << b.get_depth() << endl;
}
return 0;
}
问题 C: DS树–二叉树之最大路径
题目描述
给定一颗二叉树的逻辑结构(先序遍历的结果,空树用字符‘0’表示,例如AB0C00D00),建立该二叉树的二叉链式存储结构
二叉树的每个结点都有一个权值,从根结点到每个叶子结点将形成一条路径,每条路径的权值等于路径上所有结点的权值和。编程求出二叉树的最大路径权值。如下图所示,共有4个叶子即有4条路径,
路径1权值=5 + 4 + 11 + 7 = 27 路径2权值=5 + 4 + 11 + 2 = 22
路径3权值=5 + 8 + 13 = 26 路径4权值=5 + 8 + 4 + 1 = 18
可计算出最大路径权值是27。
该树输入的先序遍历结果为ABCD00E000FG00H0I00,各结点权值为:
A-5,B-4,C-11,D-7,E-2,F-8,G-13,H-4,I-1
输入
第一行输入一个整数t,表示有t个测试数据
第二行输入一棵二叉树的先序遍历,每个结点用字母表示
第三行先输入n表示二叉树的结点数量,然后输入每个结点的权值,权值顺序与前面结点输入顺序对应
以此类推输入下一棵二叉树
输出
每行输出每棵二叉树的最大路径权值,如果最大路径权值有重复,只输出1个
样例输入
2
AB0C00D00
4 5 3 2 6
ABCD00E000FG00H0I00
9 5 4 11 7 2 8 13 4 1
样例输出
11
27
AC代码
#include<bits/stdc++.h>
using namespace std;
struct BTree_node
{
char date;
BTree_node* left, * right;
int weight;
void set(char c, BTree_node* l = NULL, BTree_node* r = NULL, int w = 0) { date = c; left = l; right = r; weight = 1; }
};
class BTree {
BTree_node* root;
int max_path(BTree_node*node) {
if (!node)
return 0;
int left_max_path = max_path(node->left);
int right_max_path = max_path(node->right);
return node->weight + (left_max_path > right_max_path ? left_max_path : right_max_path);
}
void input_weight(BTree_node*node){
if (!node)
return;
cin >> node->weight;
input_weight(node->left);
input_weight(node->right);
}
void preorder_tra(BTree_node* node) {
if (!node)
return;
cout << node->date;
preorder_tra(node->left);
preorder_tra(node->right);
}
void inorder_tra(BTree_node* node)
{
if (!node)
return;
inorder_tra(node->left);
cout << node->date;
inorder_tra(node->right);
}
void postorder_tra(BTree_node* node)
{
if (!node)
return;
postorder_tra(node->left);
postorder_tra(node->right);
cout << node->date;
}
void createTree(BTree_node*& node) {
char ch;
cin >> ch;
if ('0' == ch) {
node = NULL;
return;
}
node = new BTree_node;
node->set(ch);
createTree(node->left);
createTree(node->right);
}
void del_tree(BTree_node* node) {
if (!node) {
delete node;
return;
}
del_tree(node->left);
del_tree(node->right);
delete node;
}
int get_depth(BTree_node* node) {
if (node == NULL)
return 0;
int left_depth = get_depth(node->left);
int right_depth = get_depth(node->right);
return 1 + (left_depth > right_depth ? left_depth : right_depth);
}
public:
BTree() { root = NULL; }
void createTree() { createTree(root); }
void preorder_tra() { preorder_tra(root); cout << endl; }
void inorder_tra() { inorder_tra(root); cout << endl; }
void postorder_tra() { postorder_tra(root); cout << endl; }
~BTree() { del_tree(root); }
int get_depth() { return get_depth(root); }
void input_weight() { int n; cin >> n; input_weight(root); }
int max_path() { return max_path(root); }
};
int main() {
int n;
cin >> n;
while (n--) {
BTree b;
b.createTree();
b.input_weight();
//b.postorder_tra();
//b.input_weight();
cout << b.max_path() << endl;
//cout << b.get_depth() << endl;
}
return 0;
}
问题 D: DS树–带权路径和
题目描述
计算一棵二叉树的带权路径总和,即求赫夫曼树的带权路径和。
已知一棵二叉树的叶子权值,该二叉树的带权案路径和APL等于叶子权值乘于根节点到叶子的分支数,然后求总和。如下图中,叶子都用大写字母表示,权值对应为:A-7,B-6,C-2,D-3
树的带权路径和 = 71 + 62 + 23 + 33 = 34
本题二叉树的创建参考前面的方法
输入
第一行输入一个整数t,表示有t个二叉树
第二行输入一棵二叉树的先序遍历结果,空树用字符‘0’表示,注意输入全是英文字母和0,其中大写字母表示叶子
第三行先输入n表示有n个叶子,接着输入n个数据表示n个叶子的权值,权值的顺序和前面输入的大写字母顺序对应
以此类推输入下一棵二叉树
输出
输出每一棵二叉树的带权路径和
样例输入
2
xA00tB00zC00D00
4 7 6 2 3
ab0C00D00
2 10 20
样例输出
34
40
AC代码
#include<bits/stdc++.h>
using namespace std;
struct BTree_node
{
char date;
BTree_node* left, * right;
int weight;
void set(char c, BTree_node* l = NULL, BTree_node* r = NULL, int w = 0) { date = c; left = l; right = r; weight = 1; depth = 0; }
int depth;
};
class BTree {
BTree_node* root;
int max_path(BTree_node* node) {
if (!node)
return 0;
int left_max_path = max_path(node->left);
int right_max_path = max_path(node->right);
return node->weight + (left_max_path > right_max_path ? left_max_path : right_max_path);
}
void input_weight(BTree_node* node) {
if (!node)
return;
if (!node->left && !node->right)
cin >> node->weight;
input_weight(node->left);
input_weight(node->right);
}
void preorder_tra(BTree_node* node) {
if (!node)
return;
cout << node->date;
preorder_tra(node->left);
preorder_tra(node->right);
}
void inorder_tra(BTree_node* node)
{
if (!node)
return;
inorder_tra(node->left);
cout << node->date;
inorder_tra(node->right);
}
void postorder_tra(BTree_node* node)
{
if (!node)
return;
postorder_tra(node->left);
postorder_tra(node->right);
cout << node->date;
}
void createTree(BTree_node*& node, int depth = 0) {
char ch;
cin >> ch;
//cout << "#---- " << ch << endl;
if ('0' == ch) {
node = NULL;
return;
}
node = new BTree_node;
node->set(ch);
node->depth = depth;
createTree(node->left, depth + 1);
createTree(node->right, depth + 1);
}
void del_tree(BTree_node* node) {
if (!node) {
delete node;
return;
}
del_tree(node->left);
del_tree(node->right);
delete node;
}
int get_depth(BTree_node* node) {
if (node == NULL)
return 0;
int left_depth = get_depth(node->left);
int right_depth = get_depth(node->right);
return 1 + (left_depth > right_depth ? left_depth : right_depth);
}
public:
BTree() { root = NULL; }
void createTree() { createTree(root); }
void preorder_tra() { preorder_tra(root); cout << endl; }
void inorder_tra() { inorder_tra(root); cout << endl; }
void postorder_tra() { postorder_tra(root); cout << endl; }
~BTree() { del_tree(root); }
int get_depth() { return get_depth(root); }
void input_weight() { int n; cin >> n; input_weight(root); }
int max_path() { return max_path(root); }
int count_path() {
int cnt = 0;
stack<BTree_node*>s;
s.push(root);
while (!s.empty()) {
BTree_node* cur_node = s.top();
s.pop();
if (!cur_node)
continue;
s.push(cur_node->left);
s.push(cur_node->right);
if (!cur_node->left && !cur_node->right)
cnt += cur_node->depth * cur_node->weight;
}
return cnt;
}
};
int main() {
int n;
cin >> n;
while (n--) {
BTree b;
b.createTree();
b.input_weight();
//b.postorder_tra();
//b.input_weight();
//cout << b.max_path() << endl;
cout << b.count_path() << endl;
//cout << b.get_depth() << endl;
}
return 0;
}
问题 E: DS森林叶子编码
题目描述
给定一组森林,编写程序生成对应的二叉树,输出这颗二叉树叶结点对应的二进制编码.规定二叉树的左边由0表示,二叉树的右边由1表示。
输入
输入:
N B 表示N个树,每结点最多B个分支
第2行至第N+1行,每个树的先序遍历
输出
每行表示一个叶结点对应的二进制编码.
样例输入
3 3
A B 0 0 0 C 0 0 0 D 0 0 0
E F 0 0 0 0 0
G H 0 0 0 I J 0 0 0 0 0 0
样例输出
0 1 1
1 0
1 1 0 1 0
说明
当时是2020年11月9日,这题我没有做。请读者自行求解并留言。