7-4 哈夫曼编码
本题要求字符的哈夫曼编码,注意建立的哈夫曼树严格按照左小右次小的顺序,并且哈夫曼编码时严格按照左‘0’右‘1’进行编码。
输入格式:
输入是各个字符在通信中出现的频率
输出格式:
输出是各个字符的哈夫曼编码,每个字母占一行
输入样例
A:2
B:3
C:6
D:7
E:10
F:19
G:21
H:32
输出样例
A:10000
B:10001
C:1001
D:1010
E:1011
F:00
G:01
H:11
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100;
#define CHARLEN 50;
typedef char **HuffmanCode;
//字符串数组类型
struct HuffNode //定义哈夫曼树结点
{
int weight; //权值
char name;
int parent, leftchild, rightchild; //父结点与左右孩子
};
typedef struct HuffNode *HtNode;
typedef struct HuffTreeNode //定义哈夫曼树
{
int n; //哈夫曼树叶子结点个数
int root; //哈夫曼树树根
HtNode ht; //指向哈夫曼树的指针
}*HuffTree;
int count=0;
int *GetFrequency(int num, char * name) //读入自选文件或默认文件进行字频分析。
{
int i;
int LEN = CHARLEN //50
int *freq = (int *)malloc(sizeof(int)*LEN);
//初始化fre数组
for (i = 0; i < LEN; i++){
freq[i] = 0;
}
char ch;
int n;
for(i = 0;i<num;i++){
scanf("%c", &ch);
getchar();
scanf("%d", &n);
getchar();
freq[ch - 0x41] = n;
name[ch - 0x41] = ch;
}
return freq;
}
//n为叶结点个数
HuffTree CreateHuffmanTree(int n, int *w, char*name)
{
HuffTree pht;
int i, j, x1, x2, min1, min2;
pht = (HuffTree)malloc(sizeof(struct HuffTreeNode));
if (pht == NULL){
printf("Out of space!!\n");
return pht;
}
//为哈夫曼树申请2*N-1个空间
pht->ht = (HtNode)malloc(sizeof(struct HuffNode)*(2 * n - 1));
if (pht->ht == NULL){
printf("Out of space!!\n");
return pht;
}
//初始化哈夫曼树
for (i = 0; i < 2 * n - 1; i++){
pht->ht[i].leftchild = -1; //初始化叶结点左孩子
pht->ht[i].rightchild = -1; //初始化叶结点右孩子
pht->ht[i].parent = -1; //初始化叶结点的父亲
if (i < n){
pht->ht[i].weight = w[i];
pht->ht[i].name = name[i];
}
else
pht->ht[i].weight = -1;
}
for (i = 0; i < n - 1; i++){
min1 = MAX; //m1代表极小值
min2 = MAX; //m2代表次小值
x1 = -1; //极小值下标
x2 = -1; //次小值下标
//找到极小值下标x1并把极小值赋值给m1
for (j = 0; j < n + i; j++){
if (pht->ht[j].weight < min1&&pht->ht[j].parent == -1){
min2 = min1;
x2 = x1;
min1 = pht->ht[j].weight;
x1 = j;
}
//找到次小值下标x2并把次小值赋值给min2
else if (pht->ht[j].weight < min2&&pht->ht[j].parent == -1){
min2 = pht->ht[j].weight;
x2 = j;
}
}
//构建x1,x2的父结点
pht->ht[x1].parent = n + i; //x1父结点下标
pht->ht[x2].parent = n + i; //x2父结点下标
pht->ht[n + i].weight = min1 + min2;//父结点的权值为极小值加次小值
pht->ht[n + i].leftchild = x1; //父结点的左孩子为x1
pht->ht[n + i].rightchild = x2; //父结点的右孩子的x2
}
pht->root = 2 * n - 2;//哈夫曼树根结点位置
pht->n = n;
return pht;
}
void CreateHuffmanCode(HuffTree pht,HuffmanCode *HC, int n)
{
//分配n个字符串编码的空间
*HC = (HuffmanCode)malloc(sizeof(char*)*(n));
//开辟一个长度为n的字符数组用来临时存放编码
char* cd = (char*)malloc(sizeof(char)*n);
cd[n-1] = '\0'; //字符串结束符
int i;
for(i = 0; i < n; i++)
{
int start = n-1; //从字符数组的末尾开始赋值
int c = i; //
int f = pht->ht[i].parent; //找出父节点
//当父结点为-1时,说明到达根节点,编码结束
while(f != -1)
{
start--;
//结点c是f的左孩子,则生成代码0,否则就是右孩子生成代码1
if(pht->ht[f].leftchild == c)
cd[start] = '0';
else
cd[start] = '1';
//将父结点作为新的子树,f为新子树的父节点
c = f;
f = pht->ht[f].parent;
}
//为第i个字符串编码分配大小合适的空间,把临时存放的复制进去
(*HC)[i] = (char*)malloc(sizeof(char)*(n-start));
//从start的位置开始复制
strcpy((*HC)[i], &cd[start]);
}
free(cd);
}
int main()
{
int i;
int *text;//存放字符的频率
char name[50];//存放字符的名字
int num = 8;//节点数量
text = GetFrequency(num, name);//获得字符频率
HuffTree pht; //定义哈夫曼树
HuffmanCode HC; //哈夫曼编码指针(二重指针)
pht = CreateHuffmanTree(num, text, name); //创建哈夫曼树
CreateHuffmanCode(pht,&HC,num); //创建哈夫曼编码表
for(i = 0;i < num;i++) //位置一样的,所以遍历即可
{
if(i<num-1){
printf("%c:%s\n",pht->ht[i].name, HC[i]);
}
else{
printf("%c:%s",pht->ht[i].name, HC[i]);
}
}
return 0;
}