1.哈夫曼树的思想:给出一个权值序列,在序列里选第一小和第二小的两个权值,以它们为左右子树构建一棵二叉树,从森林里面删除这两个树再把新树添加进去,直到只有一棵树为止
2.计算带权路径长度
【问题描述】 输入一串正整数,正整数之间用空格键分开,请建立一棵哈夫曼树,以输入的数字作为叶子节点,求这棵哈夫曼树的带权路径长度。
【输入形式】 首先输入正整数的个数n,然后是对应的n个正整数,正整数个数不超过10个
【输出形式】 输出创建的哈夫曼树的带权路径总长度
【样例输入】
5
4 5 6 7 8
【样例输出】
69
select函数,给定一个数组和寻找区间,以及两个需要传出的值(函数的返回值只有一个),当parent不是0,即这个节点是某个节点的孩子,跳过这次循环,然后进行判断和赋值,接下来解析creat,首先原始数组有n个元素,按照两个元素合成一棵树的思想,又需要n-1个节点,总共需要2*n-1个节点初始化,又因为范围原因,m赋值为2*n,首先初始化0到n-1个节点,以权重为依据初始化,再对n到2*n-1个节点进行普通初始化,然后对n到2*n-1个节点进行合并操作,就是将新树的权重改为两个最小值的权重之和,在更新新树的左右节点以及两个最小值的父节点,接下来是下一个函数,找到最后一棵树的位置,然后遍历树,再进行权重运算(也就是权重乘高度,从0开始),在下标为2*n-2的位置为树的根节点,进行遍历
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
typedef struct tree
{
int weight;
int parent;
int left;
int right;
}tree;
void select(tree* arr, int limit, int& min1, int& min2)
{
min1 = -1;
min2 = -1;
int fmin = 999;
int smin = 999;
for (int i = 0; i < limit; i++)
{
if (arr[i].parent != -1)
{
continue;
}
else
{
if (arr[i].weight < fmin)
{
smin = fmin;
min2 = min1;
fmin = i;
min1 = i;
}
else if (arr[i].weight < smin)
{
smin = arr[i].weight;
min2 = i;
}
}
}
}
void creat(tree* arr, int *data, int n)
{
for (int i = 0; i < n; i++)
{
arr[i].parent = -1;
arr[i].weight = data[i];
arr[i].left = arr[i].right = -1;
}
int m = 2 * n-1;
for (int i = n; i < m; i++)
{
arr[i].parent = -1;
arr[i].weight = -1;
arr[i].left = arr[i].right = -1;
}
for (int i = n; i < m; i++)
{
int min1;
int min2;
select(arr, i, min1, min2);
arr[i].weight = arr[min1].weight + arr[min2].weight;
arr[min1].parent = arr[min2].parent = i;
arr[i].left = min1;
arr[i].right = min2;
}
}
int sum = 0;
void solve(tree* arr, int pos, int h)
{
if (arr[pos].left != -1)
{
solve(arr, arr[pos].left, h + 1);
}
if ( arr[pos].right==-1 && arr[pos].left == -1)
{
sum += arr[pos].weight * h;
}
if (arr[pos].right!= -1)
{
solve(arr, arr[pos].right, h + 1);
}
}
int main()
{
int arr[100];
int count = 0;
cin >> count;
for (int i = 0; i < count; i++)
{
cin >> arr[i];
}
tree point[100];
creat(point,arr, count);
solve(point, 2 * count-2, 0);
cout << sum;
return 0;
}
哈夫曼树与哈夫曼编码
【问题描述】读入n个字符所对应的权值,自底向上构造一棵哈夫曼树,自顶向下生成每一个字符对应的哈夫曼编码,并依次输出。另,求解某字符串的哈夫曼编码,求解某01序列的译码。
【输入形式】输入的第一行包含一个正整数n,表示共有n个字符需要编码。其中n不超过100。第二行中有n个用空格隔开的正整数,分别表示n个字符的权值,依次按照abcd...的默认顺序给出。然后是某字符串和某01序列。
【输出形式】前n行,每行一个字符串,表示对应字符的哈夫曼编码。然后是某字符串的哈夫曼编码,某01序列的译码。
【注意】保证每次左子树比右子树的权值小;如出现相同权值的,则先出现的在左子树,即下标小的在左子树。
【样例输入】
8
5 29 7 8 14 23 3 11
aabchg
00011110111111001
【样例输出】
0001
10
1110
1111
110
01
0000
001
000100011011100010000
acdef
现在来解析两个函数,outpom为输出哈夫曼编码,limit为树根节点所在位置,pos为查找位置,从查找位置的父节点开始打印,如果pos是左节点打印0,是右节点打印1,然后向上继续查找(哈夫曼编码为从根节点到子节点的路径),由于以上原因,要反向打印,翻译函数解析如下:next为树根位置,输入哈夫曼编码,再遍历,寻找从根到给定节点的路径,如果为0则移向左孩子,如果为1则移向右孩子,如果已经移动到叶子节点则打印该点的字母编号,并将next回退到根节点位置
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
typedef struct tree
{
int weight;
int parent;
int left;
int right;
}tree;
void select(tree* arr, int limit, int& min1, int& min2)
{
min1 = -1;
min2 = -1;
int fmin = 999;
int smin = 999;
for (int i = 0; i < limit; i++)
{
if (arr[i].parent != -1)
{
continue;
}
else
{
if (arr[i].weight < fmin)
{
smin = fmin;
min2 = min1;
fmin = i;
min1 = i;
}
else if (arr[i].weight < smin)
{
smin = arr[i].weight;
min2 = i;
}
}
}
}
void creat(tree* arr, int *data, int n)
{
for (int i = 0; i < n; i++)
{
arr[i].parent = -1;
arr[i].weight = data[i];
arr[i].left = arr[i].right = -1;
}
int m = 2 * n-1;
for (int i = n; i < m; i++)
{
arr[i].parent = -1;
arr[i].weight = -1;
arr[i].left = arr[i].right = -1;
}
for (int i = n; i < m; i++)
{
int min1;
int min2;
select(arr, i, min1, min2);
arr[i].weight = arr[min1].weight + arr[min2].weight;
arr[min1].parent = arr[min2].parent = i;
arr[i].left = min1;
arr[i].right = min2;
}
}
void outpom(tree* arr, int limit, int pos)
{
int num[100];
int count = 0;
int p = arr[pos].parent;
while (p != 0)
{
if (pos == arr[p].left)
{
num[count++] = 0;
}
if (pos == arr[p].right)
{
num[count++] = 1;
}
pos = p;
p = arr[pos].parent;
}
while (count--)
{
cout << num[count];
}
}
void inpom(tree* arr, int limit)
{
string code;
cin >> code;
int pos = 0;
int next = limit;
while (pos < code.size())
{
if (code[pos] == '0')
{
next = arr[next].left;
}
else if (code[pos] == '1')
{
next = arr[next].right;
}
if (arr[next].left == -1 && arr[next].right == -1)
{
char c = 'a';
c = c + next;
cout << c;
next = limit;
}
pos++;
}
}
int main()
{
int leave;
cin >> leave;
int w[100];
int i = 0;
for (i = 0; i < leave ; i++)
{
cin >> w[i];
}
tree* arr;
creat(arr, w, leave);
for (i = 0; i < leave; i++)
{
outpom(arr, 2 * leave - 2, i);
cout << endl;
}
char s[20];
cin >> s;
for (i = 0; s[i] != '\0'; i++)
{
int ques = s[i] - 97 + 1;
outpom(arr, 2 * leave - 2, ques);
}
cout << endl;
inpom(arr, 2 * leave - 2);
return 0;
}