@Sparks
2022-03-05
gxust的数据结构实验
题目
编写一个哈夫曼编码译码程序。
按词频从小到大的顺序给出各个字符(不超过30个)的词频,根据词频构造哈夫曼树,给出每个字符的哈夫曼编码,并对给出的语句进行译码。
为确保构建的哈夫曼树唯一,本题做如下限定:
(1)选择根结点权值最小的两棵二叉树时,选取权值较小者作为左子树。
(2)若多棵二叉树根结点权值相等,按先后次序分左右,先出现的作为左子树,后出现的作为右子树。
生成哈夫曼编码时,哈夫曼树左分支标记为0,右分支标记为1。
输入格式:
第一行输入字符个数n;
第二行到第n行输入相应的字符及其词频(可以是整数,与可以是小数);
最后一行输入需进行译码的串。
输出格式:
首先按树的先序顺序输出所有字符的编码,每个编码占一行;
最后一行输出需译码的原文,加上original:字样。
输出中均无空格
输入样例:
3
m1
n1
c2
10110
输出样例:
c:0
m:10
n:11
original:mnc
分析
关键就是哈夫曼编码的构造和译码,但是这里有一个难点:分离字符和数字,还有数字不只有整数还有浮点数
代码
因为某些原因我不能提供完整代码,具体实现还是要靠各位同学思考和调试。
注释很少是因为我一路写下来的,没怎么注释,代码只能参考,毕竟我也是花了很多时间才写出来的
#include<stdio.h>
#include<stdlib.h>
#define MAXVALUE 32767
typedef struct hf{//哈夫曼树
int weight;
int parent;
int lchild;
int rchild;
}Htree;
typedef struct hc{//哈夫曼编码
int* bit;//存放当前结点的哈夫曼编码
int start;//bit[start]-bit[n]存放哈夫曼编码
char ch;
}Hcode;
Htree* InitHtree(int* w,int leght){
int i;
Htree* HT = (Htree*)malloc(sizeof(Htree)*(2*leght-1));
for(i = 0; i<leght; i++){
HT[i].weight = w[i];
HT[i].parent = -1;
HT[i].lchild = -1;
HT[i].rchild = -1;
}
return HT;
}
Hcode* InitHcode(int leght,char* ch){
int i;
Hcode* HC = (Hcode*)malloc(sizeof(Hcode)*leght);
for(i = 0; i<leght; i++){
HC[i].bit = (int*)malloc(sizeof(int)*leght);
HC[i].ch = ch[i];
}
return HC;
}
void CreateHuffTree(Htree* HT,int leght){ //构造哈夫曼树
int i,j,a,b,min1,min2;
int l = 2*leght-1;
for(i = leght;i<l;i++){
a = MAXVALUE;
b = MAXVALUE;
min1 = 0;
min2 = 0;
for(j = 0; j < leght+i; j++){ //选取最小的权值
if(HT[j].parent == -1 && HT[j].weight < a){
a = HT[j].weight;
min1 = j;
}
}
for(j = 0; j < leght+i; j++){ //选取次小的权值
if(HT[j].parent == -1 && HT[j].weight < b && j!= min1){
b = HT[j].weight;
min2 = j;
}
}
HT[i].weight = HT[min1].weight+HT[min2].weight;
HT[i].parent = -1;
HT[i].lchild = min1;
HT[i].rchild = min2;
HT[min1].parent = i;
HT[min2].parent = i;
leght++;//没有必要。
}
}
void PrintHuffTree(Htree* HT,Hcode* HC,int index,int leght){//输出哈夫曼树
int i;
printf("\n哈夫曼树各项数据如下表所示:\n");
printf(" 结点i weight parent lchid rchild\n");
for(i=0;i<index;i++){
printf("\t%d\t%d\t%d\t%d\t%d\n",i,HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);
}
}
void CreateHuffCode(Hcode* HC,Htree* HT,int leght){//构造哈夫曼编码
int i,j,c,p;
for(i = 0; i<leght;i++){
Hcode* cd = (Hcode*)malloc(sizeof(Hcode));
cd->bit = (int*)malloc(sizeof(int)*leght);
cd->start = leght-1;
c = i;
p = HT[c].parent;
while(p!=-1){
if(HT[p].lchild == c){
cd->bit[cd->start] = 0;
}else{
cd->bit[cd->start] = 1;
}
cd->start--;
c = p;
p = HT[c].parent;
}
for(j = cd->start+1; j < leght; j++){
HC[i].bit[j] = cd->bit[j];
}
HC[i].start = cd->start;
free(cd);
}
}
void PrintHuffcode(Hcode* HC,int leght){ //输出每个叶子结点的哈夫曼编码
int i,j;
printf("\n每个叶子结点的哈夫曼编码为:\n");
for(i = 0;i < leght;i++){
for(j = HC[i].start+1; j < leght; j++){
printf("%d",HC[i].bit[j]);
}
printf("------------>>>%d",i);
printf("\n");
}
}
void Decode(Htree* HT,Hcode* HC,int lenght,char* mch){//译码
printf("original:");
int index;
int i;
int j = 0;
index = 2*lenght-2;
while(mch[j]!='\0'){
if(mch[j] == '0'){
index = HT[index].lchild;
}else{
index = HT[index].rchild;
}
if(HT[index].lchild == -1 && HT[index].rchild == -1){
printf("%c",HC[index].ch);
index = 2*lenght-2;
}
j++;
}
printf("\n");
}
int main(void){
int w[3] = {1,1,2};
char ch[3] = {'m','n','c'};
char mch[MAXVALUE] = {"011100111001110011100111001110"};
int leght = 3;
int i;
Htree * HT = InitHtree(w,leght);
Hcode * HC = InitHcode(leght,ch);
CreateHuffTree(HT,leght);
CreateHuffCode(HC,HT,leght);
PrintHuffTree(HT,HC,2*leght-2,leght);
PrintHuffcode(HC,leght);
Decode(HT,HC,leght,mch);
return 0;
}
输出:
哈夫曼树各项数据如下表所示:
结点i weight parent lchid rchild
0 1 3 -1 -1
1 1 3 -1 -1
2 2 4 -1 -1
3 2 4 0 1
每个叶子结点的哈夫曼编码为:
10------------>>>0
11------------>>>1
0------------>>>2
original:cnmcnmcnmcnmcnmcnm
熬夜写过的,头都秃了