从键盘接收一串电文字符,输出对应的Huffman编码。同时,能翻译由Huffman编码生成的代码串,输出对应的电文字符串。
(2)设计要求
完成如下菜单的功能
Huffman树的建立
Huffman树的输出
生成Huffman编码
译码并输出
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
// 定义一个字母及其频度结构体
struct FREQ
{
unsigned char alpha;
int freq;
};
typedef struct FREQ FREQ;
// 定义一个哈夫曼表结构体
struct HUFFMAN_TABLE
{
unsigned char alpha;
int freq;
int lChild;
int rChild;
unsigned char accessFlag;
char *hufCode;
};
typedef struct HUFFMAN_TABLE HUFFMAN_TABLE;
#define NOT_FOUND 0
#define FOUND 1
FREQ *getAlphaFreq(char *str, int *alphaKind, int *alpha);
int findMinFreqAlpha(HUFFMAN_TABLE *hufTab, int account);
HUFFMAN_TABLE *initHufTab(FREQ *freq, int alphaCount);
HUFFMAN_TABLE *createHufTab(FREQ *freq, int alphaCount);
void destroyHufTab(HUFFMAN_TABLE *huf, int alphaCount);
void showHufTree(HUFFMAN_TABLE *huf, int alphaCount);
void makeHuffmanCode(HUFFMAN_TABLE *huf, int root, int codeIndex, char *code);
int getHufStringLen(HUFFMAN_TABLE *huf, int alphaCount);
char *codingString(HUFFMAN_TABLE *huf, int alphaCount, int *alphaHufIndex, char *string);
char *decodingString(HUFFMAN_TABLE *huf, int alphaCount, char *string);
char *decodingString(HUFFMAN_TABLE *huf, int alphaCount, char *string)
{
int i = 0;
int root = 2 * (alphaCount - 1);
char *result;
int t = 0;
int strLen = getHufStringLen(huf, alphaCount);
result = (char *)malloc(sizeof(char) * huf[root].freq + 1);
while (i <= strLen)
{
if (-1 != huf[root].lChild)
{
root = string[i++] == '1' ? huf[root].lChild : huf[root].rChild;
}
else
{
result[t++] = huf[root].alpha;
root = 2 * (alphaCount - 1);
}
}
result[t] = 0;
return result;
}
char *codingString(HUFFMAN_TABLE *huf, int alphaCount, int *alphaHufIndex, char *string)
{
char *codestr;
int i;
codestr = (char *)calloc(sizeof(char), getHufStringLen(huf, alphaCount) + 1);
for (i = 0; string[i]; i++)
{
strcat(codestr, huf[alphaHufIndex[string[i]]].hufCode);
}
return codestr;
}
int getHufStringLen(HUFFMAN_TABLE *huf, int alphaCount)
{
int sum = 0;
int i;
for (i = 0; i < alphaCount; i++)
{
sum += huf[i].freq * strlen(huf[i].hufCode);
}
return sum;
}
void makeHuffmanCode(HUFFMAN_TABLE *huf, int root, int codeIndex, char *code)
{
if (-1 == huf[root].lChild)
{
code[codeIndex] = 0;
strcpy(huf[root].hufCode, code);
}
else
{
code[codeIndex] = '1';
makeHuffmanCode(huf, huf[root].lChild, codeIndex + 1, code);
code[codeIndex] = '0';
makeHuffmanCode(huf, huf[root].rChild, codeIndex + 1, code);
}
}
void showHufTree(HUFFMAN_TABLE *huf, int alphaCount)
{
int i;
printf("下标 字符 频度 左孩子 右孩子 Flag 哈夫曼编码\n");
for (i = 0; i < 2 * alphaCount - 1; i++)
{
printf("%4d\t%4c\t%4d\t%6d\t%6d\t%4d\t%s\n",
i,
huf[i].alpha,
huf[i].freq,
huf[i].lChild,
huf[i].rChild,
huf[i].accessFlag,
huf[i].hufCode);
}
}
void destroyHufTab(HUFFMAN_TABLE *huf, int alphaCount)
{
int i;
for (i = 0; i < alphaCount; i++)
{
free(huf[i].hufCode);
}
free(huf);
}
HUFFMAN_TABLE *createHufTab(FREQ *freq, int alphaCount)
{
HUFFMAN_TABLE *huf;
int i;
int lChild, rChild;
huf = initHufTab(freq, alphaCount);
for (i = 0; i < alphaCount; i++)
{
lChild = findMinFreqAlpha(huf, alphaCount + i);
rChild = findMinFreqAlpha(huf, alphaCount + i);
huf[alphaCount + i].alpha = (unsigned char)NULL;
huf[alphaCount + i].freq = huf[lChild].freq + huf[rChild].freq;
huf[alphaCount + i].lChild = lChild;
huf[alphaCount + i].rChild = rChild;
huf[alphaCount + i].accessFlag = NOT_FOUND;
huf[alphaCount + i].hufCode = NULL;
}
return huf;
}
HUFFMAN_TABLE *initHufTab(FREQ *freq, int alphaCount)
{
HUFFMAN_TABLE *huf;
int i;
huf = (HUFFMAN_TABLE *)malloc(sizeof(HUFFMAN_TABLE) * (2 * alphaCount - 1));
for (i = 0; i < alphaCount; i++)
{
huf[i].alpha = freq[i].alpha;
huf[i].freq = freq[i].freq;
huf[i].lChild = huf[i].rChild = -1;
huf[i].accessFlag = NOT_FOUND;
huf[i].hufCode = (char *)calloc(sizeof(char), alphaCount);
}
return huf;
}
int findMinFreqAlpha(HUFFMAN_TABLE *hufTab, int account)
{
int minIndex = -1;
int i;
for (i = 0; i < account; i++)
{
if (hufTab[i].accessFlag == NOT_FOUND &&
(minIndex == -1 || hufTab[i].freq < hufTab[minIndex].freq))
minIndex = i;
}
hufTab[minIndex].accessFlag = FOUND;
return minIndex;
}
FREQ *getAlphaFreq(char *str, int *count, int *alpha)
{
FREQ *p = NULL; // 获得的字符串频度信息保存在该结构体
int cnt = 0; // 字符串种类
int i, j;
if (NULL == str)
{
printf("error: str is null\n");
return NULL;
}
for (i = 0; str[i]; i++)
{
alpha[str[i]]++; // 不同位置的相同字符是数组的同一个元素 ++
}
for (i = 0; i < 256; i++)
{
if (alpha[i])
{
cnt++;
}
}
p = (FREQ *)malloc(sizeof(FREQ) * cnt);
for (i = j = 0; i < 256 && j < cnt; i++)
{
if (alpha[i])
{
p[j].alpha = i; // i是对应字符的ASCII码,此处会以char类型解释
p[j].freq = alpha[i];
alpha[i] = j++;
}
}
*count = cnt;
return p;
}
int main()
{
char str[1024];
FREQ *freqPoint = NULL;
int alphaCount;
int i;
HUFFMAN_TABLE *huf = NULL;
char *code = NULL;
int alphaHufIndex[256] = {0};
char *coString = NULL;
char *deString = NULL;
int choice;
while (1)
{
printf("菜单:\n");
printf("1. Huffman树的建立\n");
printf("2. Huffman树的输出\n");
printf("3. 生成Huffman编码\n");
printf("4. 译码并输出\n");
printf("5. 退出系统\n");
printf("请选择操作(1-5): ");
scanf("%d", &choice);
switch (choice)
{
case 1:
printf("请输入一个字符串:\n");
scanf("%s", str);
freqPoint = getAlphaFreq(str, &alphaCount, alphaHufIndex);
huf = createHufTab(freqPoint, alphaCount);
code = (char *)malloc(sizeof(char *) * alphaCount);
makeHuffmanCode(huf, 2 * (alphaCount - 1), 0, code);
printf("Huffman树已建立\n");
break;
case 2:
if (huf != NULL)
{
showHufTree(huf, alphaCount);
}
else
{
printf("Huffman树尚未建立,请先选择操作1建立树\n");
}
break;
case 3:
if (huf != NULL)
{
printf("Huffman编码生成成功\n");
coString = codingString(huf, alphaCount, alphaHufIndex, str);
printf("生成的Huffman编码为:\n%s\n", coString);
}
else
{
printf("Huffman树尚未建立,请先选择操作1建立树\n");
}
break;
case 4:
if (huf != NULL && coString != NULL)
{
printf("Huffman译码并输出成功\n");
deString = decodingString(huf, alphaCount, coString);
printf("译码后的字符串为:\n%s\n", deString);
}
else
{
printf("Huffman树或编码尚未生成,请先选择操作1和3生成树和编码\n");
}
break;
case 5:
if (freqPoint != NULL)
{
free(freqPoint);
}
if (huf != NULL)
{
destroyHufTab(huf, alphaCount);
}
if (code != NULL)
{
free(code);
}
if (coString != NULL)
{
free(coString);
}
if (deString != NULL)
{
free(deString);
}
printf("退出系统\n");
return 0;
default:
printf("无效的选择,请重新输入\n");
break;
}
}
return 0;
}