1. 题目
示例输入
5 a b c d e 12 40 15 8 25
bbbaddeccbbb
示例输出
00011111110111010110110000
bbbaddeccbbb
2. 分析
分析:由于哈夫曼树中没有度为1的结点,因此一棵有n个叶子的哈夫曼树共有2n-1个结点,可以用一个大小为2n-1的数组来存放哈夫曼树的各个结点。由于每个结点同时还包含其双亲和孩子结点的信息,所以构成一个静态三叉链表。
程序调试中可以输出哈夫曼树构成的链表如下:
注意:本题中,由于编号是从0开始的,所以lchild、rchild和parent都不能用0来存储,否则无法分辨是没有双亲和孩子 或者是 双亲和孩子是第一行的结点。(因此,初始化时将其全部赋值为了-1)
初始化的Huffman树:
每一轮找出的最小和次小的行数(结点):
构建huffman树:
3. 代码
上课不听讲,写代码火葬场。
//5 a b c d e 12 40 15 8 25
//bbbaddeccbbb
#include <iostream>
#include <string>
using namespace std;
#define MAX 100
//定义哈夫曼树的结点,在表中的表现形式为一行
typedef struct{
int weight;
int lchild, rchild, parent;
char data;
}HTNode;
HTNode ht[2*MAX-1];
int code[MAX]; //临时储存字符的编码,每个字符的编码长度都不会大于MAX
int allcode[99999]; //记录编码后的二进制码
int leng = 0; //记录allcode的长度
//初始化表格
void init(int n){
for(int i=0; i<2*n-1; i++){
ht[i].lchild = -1;
ht[i].rchild = -1;
ht[i].parent = -1;
ht[i].weight = 0;
ht[i].data = '\0';
}
}
void input(int n){
char tmp[n];
int w[n];
//首先处理输入
for(int i=0; i<n; i++){
cin >> tmp[i];
}
for(int i=0; i<n; i++){
cin >> w[i];
}
//将输入填入表格
for(int i=0; i<n; i++){
ht[i].data = tmp[i];
ht[i].weight = w[i];
}
}
//传引用 &,row1和row2的更新能在调用函数中体现
//select函数的作用是找出没有parent的最小和次小的两个结点
//row1存最小,row2存次小
void select(int i, int &row1, int &row2){
int w1 = 99999, w2 = 99999;
for(int j=0; j<i; j++){
if(ht[j].parent == -1){
//若当前行的weight比两者都小
if(ht[j].weight < w1){
row2 = row1;
w2 = w1;
row1 = j;
w1 = ht[j].weight;
}
//若介于最小和次小之间
else if(ht[j].weight < w2){
row2 = j;
w2 = ht[j].weight;
}
}
}
}
void huffman(int n){
init(n);
input(n);
//开始填表,构建哈夫曼树
for(int i=n; i<2*n-1; i++){
int row1 = -1, row2 = -1;
select(i, row1, row2);
// 根据找出的最小和次小结点进行填表和更新
ht[i].lchild = row1;
ht[i].rchild = row2;
ht[row1].parent = i;
ht[row2].parent = i;
ht[i].weight = ht[row1].weight + ht[row2].weight;
}
}
void encode(string str, int n){
int len = str.length();
for(int i=0; i<len; i++){
//对要编码字符串的每一个进行编码
int tmp = n-1;
for(int j=0; j<n; j++){
//该字符对应的是第j行的字符
if(ht[j].data == str[i]){
//不是根节点时 进行向上查找(循环)
while(ht[j].parent != -1){
if(ht[ht[j].parent].lchild == j){
code[tmp] = 0;
}
else{
code[tmp] = 1;
}
j = ht[j].parent;
tmp--;
}
}
}
for(int k=tmp+1; k<n; k++){
allcode[now++] = code[k];
leng++;
}
}
for(int k=0; k<leng; k++){
cout << allcode[k];
}
cout << endl;
}
void decode(int n){
int t = 0;
while(t < leng){
int k = 2*n-2; //从根节点开始查找
//根据哈夫曼树的结构,左右子孩子应该同时存在
//树枝节点没有左右孩子
while(ht[k].lchild!=-1 && ht[k].rchild!=-1){
if(allcode[t++] == 0){
k = ht[k].lchild;
}
else{
k = ht[k].rchild;
}
}
cout << ht[k].data;
}
cout << endl;
}
int main(){
int n;
cin >> n;
huffman(n);
string str;
cin >> str;
encode(str, n);
decode(n);
return 0;
}