#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define N 30
#define M 2 * N - 1
typedef struct
{
int weight; //权值
int Parent, Lchild, Rchild; //双亲,左孩子,右孩子
}HTNode, HuffmanTree[M + 1]; //哈夫曼树,0号不使用
typedef struct
{
char ch; //字符
int WEI; //权值
}weighting;
typedef struct //堆串
{
char* s;
int len;
}HString;
typedef char* HuffmanCode[N];
void read(FILE* fp,char str[]); //读入文件
weighting* getweight(char str[], weighting w[]); //计算权值
void Printvalue(weighting w[]); //打印权值列表
void CrtHuffmanTree(HuffmanTree ht, weighting w[], int n); //建立哈夫曼树
void select(HuffmanTree ht, int k, int* s1, int* s2); //选择ht前i-1项中双亲为零且权值最小的两节点s1,s
void PrintTree(HuffmanTree ht, int n); //打印哈夫曼树
void CrtHuffmanCode(HuffmanTree ht, HuffmanCode hc, int n); //哈夫曼编码
void PrintCode(HuffmanCode hc, int n); //打印哈夫曼编码
void Decoding(char str[], weighting w[], HuffmanCode hc); //译码并打印
int main()
{
HuffmanTree H;
HuffmanCode T;
weighting WEI[10000];
HString* STR;
FILE* fp = NULL;
char str[10000];
weighting* W;
read(fp,str);
W = getweight(str, WEI); //计算权值
int len = W[0].WEI;
CrtHuffmanTree(H, W, len); //建立哈夫曼树
CrtHuffmanCode(H, T, len); //哈夫曼编码
PrintTree(H, 2 * len - 1); //打印哈夫曼树
PrintCode(T, len); //打印哈夫曼编码
Printvalue(W); //打印每个字符和其所对应的权值
Decoding(str, W, T); //译码并打印
}
//读入文件
void read(FILE* fp,char str[])
{
char filename[40];
printf("请输入文件名:\n");
gets_s(filename);
fp = fopen(filename, "r");
if (fp == NULL)
{
printf("\nERROR!\n");
exit(0);
}
fscanf(fp, "%s", str);
puts(str);
fclose(fp);
}
//构造哈夫曼树
void CrtHuffmanTree(HuffmanTree ht, weighting w[], int n)
{
int m;
m = 2 * n - 1;
int i;
//初始化哈夫曼树
for (i = 1; i <= n; i++)
{
ht[i].weight = w[i].WEI;
ht[i].Rchild = 0;
ht[i].Lchild = 0;
ht[i].Parent = 0;
}
for (i = n + 1; i <= m; i++)
{
ht[i].weight = 0;
ht[i].Rchild = 0;
ht[i].Lchild = 0;
ht[i].Parent = 0;
}
//给后面的结点赋值
for (i = n + 1; i <= m; i++)
{
//选择树中双亲为0最小的两个值
int s1, s2;
select(ht, i - 1, &s1, &s2);
ht[i].weight = ht[s1].weight + ht[s2].weight;
ht[i].Lchild = s1;
ht[i].Rchild = s2;
ht[s1].Parent = i;
ht[s2].Parent = i;
}
}
//选择ht前i-1项中双亲为零且权值最小的两节点s1,s2
void select(HuffmanTree ht, int k, int* s1, int* s2)
{
int i;
int j = 0;
int min1 = 10000;
int min2 = 10000;
for (i = 1; i <= k; i++)
{
if (ht[i].weight <= min1 && ht[i].Parent == 0)
{
*s1 = i;
j = i;
min1 = ht[i].weight;
}
}
for (i = 1; i <= k; i++)
{
if (i == j) continue;
else
{
if (ht[i].weight <= min2 && ht[i].Parent == 0)
{
*s2 = i;
min2 = ht[i].weight;
}
}
}
}
//哈夫曼编码
void CrtHuffmanCode(HuffmanTree ht, HuffmanCode hc, int n)
{
char* cd;
int i;
int c;
int p;
int start;
cd = (char*)malloc(n * sizeof(char)); //临时编码数组
cd[n - 1] = '\0'; //从叶子节点开始遍历到根,所以首先放置\0
for (i = 1; i <= n; i++) //求每个叶子结点的编码,共有n个叶子结点
{
start = n - 1; //从后开始编写编码
c = i; //c为当前节点
p = ht[i].Parent; //p为其双亲
while (p != 0) //当其不为根节点时
{
start--;
if (ht[p].Rchild == c)
{
cd[start] = '1';
}
else
{
cd[start] = '0';
}
c = p;
p = ht[p].Parent;
}
hc[i] = (char*)malloc((n - start) * sizeof(char));
strcpy(hc[i], &cd[start]);
}
free(cd);
}
//打印哈夫曼树
void PrintTree(HuffmanTree ht, int n)
{
int i;
printf("Printhuffmantree:\n");
for (i = 1; i <= n; i++)
{
printf("%d %d %d %d\n", ht[i].weight, ht[i].Parent, ht[i].Lchild, ht[i].Rchild);
}
}
//打印哈夫曼编码
void PrintCode(HuffmanCode hc, int n)
{
int i;
printf("Printcode:\n");
for (i = 1; i <= n; i++)
{
puts(hc[i]);
}
}
//计算权值
weighting* getweight(char str[], weighting* w)
{
int i = 0;
int j = 0;
int k;
int m;
int len = strlen(str); //字符串长度
for (i = 0, k = 1; i < len; i++, k++) //遍历字符串,将每一个字符记录下来,并赋初值为1
{
w[k].ch = str[i];
w[k].WEI = 1;
}
for (i = 0, k = 1; i < len; i++, k++)
{
for (j = i + 1; j <= len; j++)
{
if (str[i] == str[j])
{
w[k].WEI++;
}
}
}
for (i = 1; i <= len; i++) //遍历数组
{
for (j = i + 1; j <= len; j++)
{
if (w[i].ch == w[j].ch)
{
w[j].WEI = 0;
}
}
}
k = 1;
weighting wnew[10000];
for (i = 1; i <= len; i++)
{
if (w[i].WEI == 0) continue;
else
{
wnew[k] = w[i];
k++;
}
}
wnew[0].WEI = k - 1;
w = wnew;
return &w[0];
}
//打印权值列表
void Printvalue(weighting w[])
{
int i;
int len = w[0].WEI;
printf("Printvalue:\n");
for (i = 1; i <= len; i++)
{
printf("%c %d\n", w[i].ch, w[i].WEI);
}
}
//译码并打印
void Decoding(char str[], weighting w[], HuffmanCode hc) //字符串、权值列表、哈夫曼编码
{
HString HS[1000]; //堆串
int i;
FILE* fp;
char filename[40];
int len = strlen(str);
int length = w[0].WEI;
int j;
for (i = 0; i < len; i++) //遍历字符串
{
for (j = 1; j <= length; j++)
{
if (str[i] == w[j].ch)
{
HS[i].s = hc[j];
HS->len++;
}
}
}
for (i = 0; i < len; i++)
{
printf("%s", HS[i].s);
}
printf("\n");
printf("Please enter the filename:\n");
gets_s(filename);
errno_t err;
fp = fopen(filename, "a+");
if (fp == NULL)
{
printf("\nERROR!\n");
exit(0);
}
fprintf(fp, "\nresult:");
for (i = 0; i < len; i++)
{
fputs(HS[i].s, fp);
}
fclose(fp);
}
哈夫曼树的建立与编码
最新推荐文章于 2022-06-14 23:06:03 发布