数据结构 赫夫曼树
Posted 上山打老虎D
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构 赫夫曼树相关的知识,希望对你有一定的参考价值。
赫夫曼树
1. DS二叉树–赫夫曼树的构建与编码(含代码框架)
题目描述
给定n个权值,根据这些权值构造huffman树,并进行huffman编码
参考课本算法,注意数组访问是从位置1开始
要求:赫夫曼的构建中,默认左孩子权值不大于右孩子权值
代码框架参考如下:
输入
第一行输入t,表示有t个测试实例
第二行先输入n,表示第1个实例有n个权值,接着输入n个权值,权值全是小于1万的正整数
依此类推
输出
逐行输出每个权值对应的编码,格式如下:权值-编码
即每行先输出1个权值,再输出一个短划线,再输出对应编码,接着下一行输入下一个权值和编码。
以此类推
输入样例
1
5 15 4 4 3 2
输出样例
15-1
4-010
4-011
3-001
2-000
参考代码
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
const int MaxW = 9999;
class huffNode //结点定义
{
public:
int weight; //权值
int parent; //父结点下标
int left; //左下标
int right; //右下标
};
class huffman
{
private:
void maketree();
void selectmin(int pos, int *s1, int *s2);
public:
int len; //结点数量
int lnum; //叶子数量
huffNode *hufftree; //赫夫曼树,用数组表示
string *huffcode; //赫夫曼编码
void maketree(int n, int wt[]);
void coding();
void destroy();
};
void huffman::maketree(int n, int wt[])
{
int i;
lnum = n;
len = 2 * n - 1;
hufftree = new huffNode[2 * n];
huffcode = new string[lnum + 1];
for (i = 1; i <= len; i++)
hufftree[i].weight = wt[i - 1];
for (i = 1; i <= len; i++)
{
if (i > n)
hufftree[i].weight = 0;
hufftree[i].parent = 0;
hufftree[i].left = 0;
hufftree[i].right = 0;
}
maketree();
}
void huffman::selectmin(int pos, int *s1, int *s2)
{
int w1, w2, i;
w1 = w2 = MaxW;
*s1 = *s2 = 0;
for (i = 1; i <= pos; i++)
{
if (hufftree[i].weight < w1 && hufftree[i].parent == 0)
{
w2 = w1;
*s2 = *s1;
*s1 = i;
w1 = hufftree[i].weight;
}
else if (hufftree[i].weight < w2 && hufftree[i].parent == 0)
{
*s2 = i;
w2 = hufftree[i].weight;
}
}
}
void huffman::maketree()
{
int i, s1, s2;
for (i = lnum + 1; i <= len; i++)
{
selectmin(i - 1, &s1, &s2);
hufftree[s1].parent = i;
hufftree[s2].parent = i;
hufftree[i].left = s1;
hufftree[i].right = s2;
hufftree[i].weight = hufftree[s1].weight + hufftree[s2].weight;
}
}
void huffman::destroy()
{
len = 0;
lnum = 0;
delete[] hufftree;
delete[] huffcode;
}
void huffman::coding()
{
char *cd;
int i, c, f, start;
cd = new char[lnum];
cd[lnum - 1] = '\\0';
for (i = 1; i <= lnum; i++)
{
start = lnum - 1;
for (c = i, f = hufftree[i].parent; f != 0; c = f, f = hufftree[f].parent)
{
if (hufftree[f].left == c)
{
start--;
cd[start] = '0';
}
else
{
start--;
cd[start] = '1';
}
}
//huffcode[i] = new char[lnum-start];
huffcode[i].assign(&cd[start]);
}
delete[] cd;
}
int main()
{
int t, n, i, j;
int wt[800];
huffman myhuff;
cin >> t;
for (i = 0; i < t; i++)
{
cin >> n;
for (j = 0; j < n; j++)
cin >> wt[j];
myhuff.maketree(n, wt);
myhuff.coding();
for (j = 1; j <= n; j++)
{
cout << myhuff.hufftree[j].weight << '-';
cout << myhuff.huffcode[j] << endl;
}
myhuff.destroy();
}
return 0;
}
2. DS二叉树–赫夫曼树解码(含代码框架)
题目描述
已知赫夫曼编码算法和程序,在此基础上进行赫夫曼解码
在赫夫曼树的类定义中增加了一个公有方法:
int Decode(const string codestr, char txtstr[]);//输入编码串codestr,输出解码串txtstr
该方法如果解码成功则返回1,解码失败则返回-1,本程序增加宏定义ok表示1,error表示-1
解码方法的代码框架如下:
输入
第一行输入t,表示有t个测试实例
第二行先输入n,表示第1个实例有n个权值,接着输入n个权值,权值全是小于1万的正整数
第三行输入n个字母,表示与权值对应的字符
第四行输入k,表示要输入k个编码串
第五行起输入k个编码串
以此类推输入下一个示例
输出
每行输出解码后的字符串,如果解码失败直接输出字符串“error”,不要输出部分解码结果
输入样例
2
5 15 4 4 3 2
A B C D E
3
11111
10100001001
00000101100
4 7 5 2 4
A B C D
3
1010000
111011
111110111
输出样例
AAAAA
ABEAD
error
BBAAA
error
DCD
参考代码
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
const int MaxW = 9999;
class huffNode //结点定义
{
public:
int weight; //权值
int parent; //父结点下标
int left; //左下标
char word;
int right; //右下标
};
class huffman
{
private:
void maketree();
void selectmin(int pos, int *s1, int *s2);
public:
int len; //结点数量
int lnum; //叶子数量
huffNode *hufftree; //赫夫曼树,用数组表示
string *huffcode; //赫夫曼编码
void maketree(int n, int wt[],char ct[]);
void coding();
void destroy();
bool decode(const string codestr, char txtstr[]);
};
void huffman::maketree(int n, int wt[],char ct[])
{
int i;
lnum = n;
len = 2 * n - 1;
hufftree = new huffNode[2 * n];
huffcode = new string[lnum + 1];
for (i = 1; i <= len; i++)
{
hufftree[i].weight = wt[i - 1];
hufftree[i].word = ct[i - 1];
}
for (i = 1; i <= len; i++)
{
if (i > n)
hufftree[i].weight = 0;
hufftree[i].parent = 0;
hufftree[i].left = 0;
hufftree[i].right = 0;
}
maketree();
}
void huffman::selectmin(int pos, int *s1, int *s2)
{
int w1, w2, i;
w1 = w2 = MaxW;
*s1 = *s2 = 0;
for (i = 1; i <= pos; i++)
{
if (hufftree[i].weight < w1 && hufftree[i].parent == 0)
{
w2 = w1;
*s2 = *s1;
*s1 = i;
w1 = hufftree[i].weight;
}
else if (hufftree[i].weight < w2 && hufftree[i].parent == 0)
{
*s2 = i;
w2 = hufftree[i].weight;
}
}
}
void huffman::maketree()
{
int i, s1, s2;
for (i = lnum + 1; i <= len; i++)
{
selectmin(i - 1, &s1, &s2);
hufftree[s1].parent = i;
hufftree[s2].parent = i;
hufftree[i].left = s1;
hufftree[i].right = s2;
hufftree[i].weight = hufftree[s1].weight + hufftree[s2].weight;
}
}
void huffman::destroy()
{
len = 0;
lnum = 0;
delete[] hufftree;
delete[] huffcode;
}
void huffman::coding()
{
char *cd;
int i, c, f, start;
cd = new char[lnum];
cd[lnum - 1] = '\\0';
for (i = 1; i <= lnum; i++)
{
start = lnum - 1;
for (c = i, f = hufftree[i].parent; f != 0; c = f, f = hufftree[f].parent)
{
if (hufftree[f].left == c)
{
start--;
cd[start] = '0';
}
else
{
start--;
cd[start] = '1';
}
}
//huffcode[i] = new char[lnum-start];
huffcode[i].assign(&cd[start]);
}
delete[] cd;
}
bool huffman::decode(const string codestr, char txtstr[])
{
int i, k, c;
char ch;
c = len;
k = 0;
for (i = 0; i < codestr.size(); i++)
{
ch = codestr[i];
if (ch == '0')
{
c = hufftree[c].left;
}
else if (ch == '1')
{
c = hufftree[c].right;
}
else
{
return false;
}
if (!hufftree[c].left && !hufftree[c].right)
{
txtstr[k] = hufftree[c].word;
k++;
c = len;
}
else
{
ch = '\\0';
}
}
if (ch == '\\0')
return false;
else
{
txtstr[k] = '\\0';
}
return true;
}
int main()
{
int t, n, i, j;
int wt[800];
char ct[800];
huffman myhuff;
cin >> t;
for (i = 0; i < t; i++)
{
cin >> n;
char txtstr[800];
for (j = 0; j < n; j++)
cin >> wt[j];
for (j = 0; j < n; j++)
cin >> ct[j];
myhuff.maketree(n, wt, ct);
myhuff.coding();
cin >> n;
while(n--)
{
string codestr;
cin >> codestr;
if(myhuff.decode(codestr,txtstr))
{
cout << txtstr << endl;
}
else
{
cout << "error" << endl;
}
}
myhuff.destroy();
}
return 0;
}
3. 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
以上是关于数据结构 赫夫曼树的主要内容,如果未能解决你的问题,请参考以下文章