设计要求:针对字符集 A 及其各字符的频率值(可统计获得)给出其中给字符
哈夫曼编码,并针对一段文本(定义在 A 上)进行编码和译码,实现一个哈夫
曼编码/译码系统。
#include
#include
#include
#include
#include
#define NN 10000
#define M 2*NN-1
#define IN 0
#define OUT 1
#define MAX_INT 32767
#define PRINTLN printf("\n\n\n\n\n\n\n\n");
typedef struct
{
int wi;
char c;
int tag;
int parent, lchild, rchild;
}huffmtype;
typedef char* encodetype[NN+1];
typedef struct
{
char c;
int times;
}codetype;
void PRINT()
{
PRINTLN;
printf("\t\t\t
printf("\t\t\t
printf("\t\t\t
printf("\t\t\t
}
Huffman 编/译码器\n");
====================\n");
1.编码 2.译码 3.退出\n\n");
>>选择:");
FILE* OpenFile(char filename[20], char type[3])
{
}
FILE *fp = NULL;
if((fp = fopen(filename, type)) == NULL) exit(1);
return fp;
int ReadCode(codetype* code, FILE* fp)
{
char c;//保存某次从文件中读入字符-
int n = 1;//记录首次出现字符在数组中的下标-
int i;//循环变量-
int cnt = 1;
int tag;//标志某次读入字符是否为首次出现字符,tag=1 表示是首次出现;tag=0
表示本次读入字符为已有字符
while((c = fgetc(fp)) != EOF)//当文件没有结束时读入字符-
{
//从 fp 指向文件中读取字符,存入字符变量 c 中-
tag = 1;//假设本次读取字符为首次出现字符-
for(i = 1; i < n; i++)
{
if(c == code[i].c)//如果本次读入字符为存储在下标为 i 已有字符-
{
code[i].times++;//权值加 1-
tag = 0;//标记本字符为已有字符-
break;//在已有数组元素中找到本次读入字符,结束 for(;;)循环-
}
}
if(tag)//当本字符为首次出现字符时-
{
code[n].c = c;//把改字符存入 n 指向的数组单元中-
code[n].times = 1;//记字符出现次数为 1-
n++;//n 指向下一个数组地址-
}
}
return n - 1;//返回文件中字符集合的元素个数-
}
void InitHuffmanTree(huffmtype* huffmtree, int real_n, int real_m)//初始化-
{
int i;
for(i = real_n; i <= real_m; i++)
{
huffmtree[i].wi = 0;
huffmtree[i].c = 0;
huffmtree[i].tag = IN;
huffmtree[i].lchild = huffmtree[i].rchild = huffmtree[i].parent = 0;
}
}
void ReadDataWeight_Init(huffmtype* huffmtree, codetype* code, int real_n)//
获取权值及数值域值-
{
int i;
for(i = 1; i <= real_n; i++)//-
{
huffmtree[i].wi = code[i].times;
huffmtree[i].c = code[i].c;
huffmtree[i].tag = IN;
huffmtree[i].lchild = huffmtree[i].rchild = huffmtree[i].parent = 0;
}
}
int LeastNode(huffmtype *huffmtree, int max_i)//找到最小权值节点地址-
{
int i;
int least_i;
int max = MAX_INT;
for(i = 1; i <= max_i; i++)//遍历 1 到 max_i 节点-
{
if(huffmtree[i].wi < max && huffmtree[i].tag == IN)//若节点权值比 max 小并且
在森林中-
{
}
max = huffmtree[i].wi;//刷新 max 值-
least_i = i;//保存当前节点地址-
}
huffmtree[least_i].tag = OUT;//将最小权值节点从森林中移除-
return least_i;//返回最小节点地址
}
void Slect(huffmtype *huffmtree, int max_i, int *x1, int *x2)//找到权值最小的两
个节点,并将其下标值保存在 x1,x2 中-
{
*x1 = LeastNode(huffmtree, max_i);//计算合法最下权值下标-
*x2 = LeastNode(huffmtree, max_i);//
}
void CreatHuffmanTree(huffmtype* huffmtree, int real_n, int real_m)//创建哈弗
曼树-
{
int i;
int x1, x2;
for(i = real_n + 1; i <= real_m; i++)
{
Slect(huffmtree, i-1, &x1, &x2);//找到权值最小的两个节点,并将其下标值保
存在 x1,x2 中-
huffmtree[i].wi = huffmtree[x1].wi + huffmtree[x2].wi;//计算双气节点权值-
huffmtree[x1].parent = huffmtree[x2].parent = i;//计算双亲节点地址-
huffmtree[i].lchild = x1; huffmtree[i].rchild = x2;//计算双亲节点左右孩子地址-
}
}
void Encode(huffmtype *huffmtree, encodetype encode, int real_n)//依据已创
建的 HuffmanTree 对字符进行编码-
{
char *cd;
int i;
int start;
int c, p;
cd = (char*)malloc(real_n*sizeof(char));//cd 用来存放某次运行时当前字符编码
-
cd[real_n - 1] = '\0';//作为字符结束符-
for(i = 1; i <= real_n; i++)//对 real_n 个节点进行遍历-
{
start = real_n-1;
c = i;//c 保存当前节点地址(下标)-
p = huffmtree[i].parent;//p 保存当前节点双亲地址-
while(p)
{
start--;//计算编码的起始地址-
if(huffmtree[p].lchild == c)//若当前节点为其双亲的左孩子-
{
}
cd[start] = '0';//编码为 0-
else//若为右孩子-
{
}
cd[start] = '1';//编码为 1-
c = p;//节点前进-
p = huffmtree[p].parent;//计算前进后节点双亲节点地址-
}
encode[i] =(char*)malloc((real_n - start)*sizeof(char));//申请空间用于存放编
码-
strcpy(encode[i], &cd[start]);//将本次编码存入 encode 数组中-
}
free(cd);//释放闲置存储空间-
}
void WriteToFile(FILE *fp, encodetype encode, codetype *code, int real_n,
char *readfile)//将编码输出到文件
{
int i;
char cod[NN];
FILE *fp2;
char c;
int cnt = 1, j;
fp2 = fopen(readfile, "rt");
while((c = fgetc(fp2)) != EOF)
{
}
cod[cnt++] = c;
fclose(fp2);
for(i = 1; i < cnt; i++)
{
for(j = 1; j <=real_n; j++)
{
}
if(cod[i] == code[j].c)
{
}
break;
fprintf(fp, "%s", encode[j]);
}
fclose(fp);
}
int IsError(FILE *fp)//对打开文件进行出错判断-
{
if(!fp)
{
}
printf("\t\t\t
×打开文件错误\n");
printf("\t\t\t 任意键返回主菜单");
getch();
return 1;//文件打开失败-
return 0;//文件打开成功-
}
void GetFilename(char *filename, char type[13])//得到用户输入相关文件名
{
}
system("cls");
PRINTLN;
printf("\t\t\t %s:", type);
fflush(stdin);
gets(filename);
int PutIntoCode(codetype code[], huffmtype huffmtree[])//编码函数
{
encodetype encode;
FILE* fp;//文件类型指针-
int real_n;//用来存放字符集长度-
char readfile[20];//从 readfile 文件中读取字符,写入到 writefile 文件中-
GetFilename(readfile, "读取源文件");//从键盘读取文件名-
fp=OpenFile(readfile, "rt");//打开待编码文件-
if(IsError(fp))//判断是否正确打开文件-
{
}
return 0;//打开文件失败,返回主菜单-