运行效果图
代码
/*
数据结构之赫夫曼编码和译码(C实现)
编译器:dev-c++ 5.11
运行环境:win10 64bit
时间:2018-5-22 13:00 至 2018-5-23 22:55
By:Wain
At:STU
*/
#include<malloc.h>
#include<string.h>
#include<stdio.h>
typedef struct {
unsigned int weight; //权重(均大于0),为什么是整型?可以其它型吗?
unsigned int parent, lchild, rchild;
}HTNode, *HuffmanTree; //动态分配数组存储哈夫曼树
typedef char **HuffmanCode; //动态分配数组存储哈夫曼编码表
void Select(HuffmanTree HT, int i, int *s1, int *s2) {
//在HT[0..i-1]选择parent为0且weight最小的两个结点,其序号分别为s1和s2
int min1,min2,k,j=0;
for(k=0;k<=i-1;++k){
if(HT[k].parent==0){
if(j==0){
min1 = HT[k].weight; *s1 = k;
}else if(j==1){
if(HT[k].weight<min1){
min2 = min1; *s2 = *s1;
min1 = HT[k].weight; *s1 = k;
}else{
min2 = HT[k].weight; *s2 = k;
}
}else{
if(HT[k].weight<min1){
min2 = min1; *s2 = *s1;
min1 = HT[k].weight; *s1 = k;
}else if(HT[k].weight>=min1&&HT[k].weight<min2){
min2 = HT[k].weight; *s2 = k;
}
}
++j;
}
}
}
void HuffmanCoding(HuffmanTree *HT, HuffmanCode *HC, int *w, int n) {
//w存放n个字符的权值(均>0),构造哈夫曼树HT,并求出n个字符的哈夫曼编码HC
if (n <= 1)return;
int m = 2*n-1; //赫夫曼树有m个结点
(*HT) = (HuffmanTree)malloc(m*sizeof(HTNode));
HuffmanTree p = (*HT);
int i;
for (i=0; i<n; ++i, ++p, ++w) {
//*p = {*w,0,0,0}; //C语言貌似不能这样赋值呢
p->weight = *w;
p->parent = 0; p->lchild = -1; p->rchild = -1;
}
for (; i<m; ++i, ++p) {
//*p = {0,0,0,0};
p->weight = 0;
p->parent = 0; p->lchild = 0; p->rchild = 0;
}
for (i=n; i<m; ++i) { //建哈夫曼树
//在HT[0..i-1]选择parent为0且weight最小的两个结点,其序号分别为s1和s2
unsigned int s1, s2;
Select((*HT), i, &s1, &s2);
(*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;
}
//---从叶子到根逆向求每个字符的哈夫曼编码---
(*HC) = (HuffmanCode)malloc(n*sizeof(char *));
char *cd = (char*)malloc(n * sizeof(char));
cd[n - 1] = '\0';
int start, f, c;
for (i=0; i<n; ++i) {
start = n - 1;
for (c = i, f = (*HT)[i].parent; f != 0; c = f, f = (*HT)[f].parent){
if ((*HT)[f].lchild == c) cd[--start] = '0';
else cd[--start] = '1';
}
(*HC)[i] = (char*)malloc((n - start) * sizeof(char));
strcpy((*HC)[i], &cd[start]);
}
free(cd);
}
int main() {
int n, i;
printf("请输入需编码的字符数目n:\n");
scanf_s("%d", &n);fflush(stdin);
char *c = (char*)malloc(n * sizeof(char)); //存字符
int *w = (int*)malloc(n * sizeof(int)); //存权重
printf("请用输入字符和对应的权值(重复%d次)\n",n);
for (i = 0; i<n; i++){
scanf("%c %d", &c[i], &w[i]);
fflush(stdin);
}
HuffmanTree HT;
HuffmanCode HC;
HuffmanCoding(&HT, &HC, w, n);
printf("\n各字符对应的编码为:\n");
for(i=0; i<n; ++i){
printf("%c %s\n",c[i],HC[i]);
}
char str[1000]; //存01二进制流
printf("\n请输入一串01二进制流:\n");
scanf("%s",&str);
char *s = str;
int p;
printf("译码为:\n");
while(*s!='\0'){
p = 2*n-2;
while(HT[p].lchild!=-1 || HT[p].rchild!=-1){
if(*s=='0') p = HT[p].lchild; //左走
else p = HT[p].rchild; //右走
++s;
}
printf("%c",c[p]);
}
free(c);
free(w);
return 0;
}
参考
《数据结构(C语言版)》严蔚敏、吴伟民 ———算法 6.12