题目:哈夫曼编译码系统(Huffman)
① 问题描述:给定n个字符的全值数组w,根据哈夫曼编码与译码规则,实现一个哈夫曼编译码系统(利用实验指导书上的27个字符的数据进行实验)。
② 利用顺序表存储Huffman树,编码结果的存储方式采用书上的结构。
③ Huffman树的构造约定如下:
l 根的权值较小的子树作为左子树,当权值相等时,先生成的作为左子树;
l 按照结点的产生次序选择权值较小的两棵子树构造Huffman树;
l 从叶子到根逆向求每个字符的Huffman编码,不采用递归方法;
l 从根结点开始实现译码,要求被译码的字符数大于20个字符。
④ 采用文件方式存储n个权值和待翻译的二进制代码,其余的数据或结构均不采用文件存储。
#include<stdlib.h>
#include<stdio.h>
#include <string.h>
int m, s1, s2; // m是总结点个数,s1,s2用于筛选出最小和第二小的两个数
typedef struct
{
unsigned int weight;
unsigned int parent, lchild, rchild;
} HTNode, *HuffmanTree;
typedef char* HuffmanCode;
void select(HuffmanTree HT, int nNode) //
{
int i, j;
for(i = 1; i <= nNode; i++)
if(!HT[i].parent)
{
s1 = i;
break;
}
for(j = i+1; j <= nNode; j++)
if(!HT[j].parent)
{
s2 = j;
break;
}
for(i = 1; i <= nNode; i++)
if((HT[i].weight < HT[s1].weight) && (!HT[i].parent) && (s2 != i))
s1 = i;
for(j = 1; j <= nNode; j++)
if((HT[j].weight < HT[s2].weight) && (!HT[j].parent) && (s1 != j))
s2 = j;
// 保证s1的weight比s2的小
if(HT[s1].weight > HT[s2].weight)
{
int tmp = s1;
s1 = s2;
s2 = tmp;
}
}
// w[]存放nNode个字符的权值,构造哈夫曼树HT,
// 并求出nNode个字符的哈夫曼编码HC
void HuffmanCoding(HuffmanTree &HT, HuffmanCode HC[], int *w, int nNode)
{
int i, j;
char *cd;
int cdlen;
if(nNode < 1)
return;
m = 2*nNode-1; //结点数
//树初始化
HT = (HTNode*) malloc ((m+1) *sizeof(HTNode)); //0号单元未用
for(i = 1; i <= nNode; i++) //初始化
{
HT[i].weight = w[i-1];
HT[i].parent = 0;
HT[i].lchild = 0;
HT[i].rchild = 0;
}
for(i = nNode+1; i <= m; i++)
{
HT[i].weight = 0;
HT[i].parent = 0;
HT[i].lchild = 0;
HT[i].rchild = 0;
}
//建立哈弗曼树
for(i = nNode+1; i <= m; i++)
{
select(HT, i-1); //选出权值最小的节点和次小的节点
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;
if(i==m)
{
printf("结点 weight parent lchild rchild");
for(j = 1; j <= i; j++)
printf("\n%4d%8d%8d%8d%8d", j, HT[j].weight, HT[j].parent, HT[j].lchild, HT[j].rchild);
}
}
//求Huffman树的编码
cd = (char *) malloc (nNode * sizeof(char)); //分配求编码的工作空间
cdlen = 0;
cd[nNode-1]='\0';
int c,f;
for(int i=1; i<=nNode; i++)
{
cdlen=nNode-1;
for(c=i,f=HT[i].parent; f!=0; c=f,f=HT[f].parent)
{
if(HT[f].lchild==c) cd[--cdlen]='0';
else cd[--cdlen]='1';
}
HC[i]=(char*)malloc((nNode-cdlen)*sizeof(char));
strcpy(HC[i],&cd[cdlen]);
}
}
int main()
{
freopen("in.txt","r",stdin);
HuffmanTree HT; // 哈夫曼树
HuffmanCode *HC; // 哈夫曼编码
int *w, nNode, i; // 权值
puts("输入结点数: ");
scanf("%d", &nNode);
HC = (HuffmanCode *) malloc (nNode* sizeof(HuffmanCode));
w = (int *) malloc (nNode * sizeof(int));
printf("输入 %d 个结点的对应的权值\n", nNode);
for(i = 0; i < nNode; i++)
scanf("%d", &w[i]);
HuffmanCoding(HT, HC, w, nNode);
puts("\n各结点的哈夫曼编码为:");
for(i = 1; i <= nNode; i++)
printf("%2d ---%4d : %s\n", i, w[i-1], HC[i]);
getchar();
}