目录
1.程序设计思路
1.框架构想
本程序的设计目的旨在使用C++实现对中英混合文本进行编码和解码,具有完整的编码解码功能和压缩率的计算功能。设计思路为先根据指定文本构建哈夫曼编码表,然后根据构建的哈夫曼编码来对指定文本进行哈夫曼编码,再将得到的哈夫曼码进行解码,得到原文本。
2.数据结构的选择
本程序的主要数据结构在于构建哈夫曼树,然而采用链表的形式的话增加后续的查找,递归遍历等操作的复杂度,故在此选用结构数组的形式来存储哈夫曼树,这会导致后续的许多算法理解起来相较于链表存储方式苦难一些,本程序对于算法的重点地方基本都有注释介绍,读者需耐心理解。这种结构数组存放哈夫曼树的方式在数据结构的教材中都有介绍,读者若理解困难可以查阅相关书籍。
/*huff树节点数据结构
weight:节点权值
parent:父节点, lchild:左子节点, rchild:右子节点
数据结构类型:列表*/
struct huff
{
int character; //存放对应字符
int weight; //存放频次
float weight1; //存放权值
int parent, lchild, rchild;
int record; //记录路径长度
};
2.相应功能的函数实现及程序变量解释
1.宏定义及全局变量的解释
本程序有一个十分重要的全局变量,即List字典查找表,该全局变量用于储存字典信息即每个字符在字典里面的位置序号,方便后续直接查找。
#define Maxlength 10000 //哈夫曼码最大长度
typedef char** HuffmanCode; //动态分配数组存放哈夫曼编码表
char** List; //建立字典查找表
2.根据指定文本构建哈夫曼树
构建哈夫曼树需要很多准备工作,例如需要将文本每个字符的频次记录下来,记录文本字符总个数。
caculate用于计数字符总个数。Get_weight函数用于记录每个字符的频次,值得特别注意的是,对于中文字符每个字符占据三个字节(本程序实现的是UTF-8格式的中文编码)而英文字符(ASCII编码格式)每个字符占据一个字节,中文字法的每个字节均为负数,英文字符的ASCII码为正数,因此可以用于此特征来区分中英文字符,在文件读入时需要注意区分开来,若读者想要实现其它类型的哈夫曼中文编码,可以自行查阅资料了解其它类型中文编码的特征来和英文字符区分开来。
int caculate (int* weight_group) //根据权值数组计算有权值的字符个数
{
int num = 0; //计数器
for (int i = 1; i < Maxlength; i++)
if (weight_group[i] != 0)
num++;
return num;
}
/*Get_weight函数说明:
函数功能:根据文本内容求得各字符的权值
入口参数:
weight_group:求的权值数组
出口参数:
文本字节总长度
变量说明:
a:存放当前字符转换成字符串的字符数组
buffer:存放文本内容
flag:对应字符在字典查找表里面的序号
i:逐个读取buffer的指针*/
int Get_weight (int* weight_group)
{
char file_name[100];
cin >> file_name;
ifstream fin (file_name);
if (!fin)
{
cout << "The file can`t be opened correctly\n";
exit (-1);
}
string buffer;
while (!fin.eof())
buffer += fin.get();
char* a;
a = (char*)malloc (4 * sizeof(char));
int flag;
int i = 0;
/*在UTF-8编码中,中文为三个字节的负数, 故在中英文文本中将两种字符分开处理即可实现中英文文本的哈夫曼编码*/
while (buffer[i] != EOF)
{
if (buffer[i] > 0)
{
a[0] = buffer[i];
a[1] = '\0';
flag = sort(a); //flag为字符对应词典查找表的下标
if (flag >=1 && flag <= Maxlength)
weight_group[flag]++;
i++;
}
if (buffer[i] < 0 && buffer[i] != EOF)
{
a[0] = buffer[i++];
a[1] = buffer[i++];
a[2] = buffer[i++];
a[3] = '\0';
flag = sort(a); //flag为字符对应词典查找表的下标
if (flag >=1 && flag <= Maxlength)
weight_group[flag]++;
}
}
return i;
}
HuffmanTree函数用于根据上述两个函数得到的权值数组和字符总个数来构建哈夫曼编码表,其中使用Minnum来找到出现频次最低的两个字符的序号。
void Changenum (int &s1, int &s2) //交换两int型数值
{
int temp;
temp = s2;
s2 = s1;
s1 =temp;
}
/*Minnum函数说明:
函数功能:找到哈夫曼树HT前n个权值中权值最小且parent为0的两个序号并分别赋值给s1, s2
入口参数:
HT:根据文本内容和权值信息构造的哈夫曼树HT
n: 查找范围
s1:第一个序号
s2:第二个序号
出口参数:无*/
void Minnum