#include <stdlib.h>
#include <stdio.h>
#include<string.h>
int weights[26] = { 0 };
char alphabet[26] = { ‘a’,‘b’,‘c’,‘d’,‘e’,‘f’,‘g’,‘h’,‘i’,‘g’,‘k’,‘l’,‘m’,‘n’,‘o’,‘p’,‘q’,‘r’,‘s’,‘t’,‘u’,‘v’,‘w’,‘x’,‘y’,‘z’ };
#define length 26
#define N 100
typedef struct
{
int weight;
int parent;
int lchild, rchild;
}HTNode, * HuffmanTree;//哈夫曼节点的类型
typedef char** HuffmanCodeTable;//哈夫曼编码表
void menu();//菜单
void CreateHuffmanTree(HuffmanTree& HT, int weights[], int n);//建立哈夫曼树
void Select(HuffmanTree HT, int n, int& min1, int& min2);//找最小的个权重和次小的权重
void CreateHuffmanCode(HuffmanTree HT, HuffmanCodeTable& HC, int n);//Huffman编码功能
void CreateHuffmanCoding(HuffmanTree HT, HuffmanCodeTable HC, char text[], char*& encode_text);//哈夫曼编码文本
void CreateHuffmandeCoding(HuffmanTree HT, HuffmanCodeTable HC, char text2[], char*& decode_text);//哈夫曼译码
void Select(HuffmanTree HT, int n, int& min1, int& min2)//找最小的个权重和次小的权重
{
min1 = min2 = 0;
for (int i = 1; i < n; i++) {//找无双亲的结点
if (HT[i].parent != 0) {
continue;
}
//当前结点为初值
if (min1 == 0) {
min1 = min2 = i;
}
else {
if (HT[i].weight <= HT[min1].weight) {//当前的结点比上个结点1权重小则换
min2 = min1;
min1 = i;
}
else if (HT[i].weight < HT[min2].weight) {//当前的结点比上个结点2权重小则换
min2 = i;
}
else if (HT[i].weight > HT[min2].weight) {//当前的结点值比初值都大仅当一次作用
if (min1 == min2) {
min2 = i;
}
}
}
}
}
void CreateHuffmanTree(HuffmanTree& HT, int weights[], int n) {//建立哈夫曼树
if (n < 1) {
return;
}
int m = 2 * n - 1;
HT = new HTNode[m + 1];//第一个空间不用
for (int i = 1; i <= m; i++) {//初始化
HT[i].parent = 0;
HT[i].lchild = HT[i].rchild = 0;
HT[i].weight = 0;
}
for (int x = 1; x <= n; x++) {
HT[x].weight = weights[x - 1];
}
for (int k = n + 1; k <= m; k++) {
int min1, min2;
Select(HT, k, min1, min2);
HT[k].weight = (HT[min1].weight + HT[min2].weight);
HT[k].lchild = min1;
HT[k].rchild = min2;
HT[min1].parent = HT[min2].parent = k;
}
}
void CreateHuffmanCode(HuffmanTree HT, HuffmanCodeTable& HC, int n) {//Huffman编码功能
HC = new char* [n + 1];//存放哈夫曼编码的数组
char* cd = new char[n];
cd[n - 1] = ‘\0’;
for (int i = 1; i <= n; i++) {//对每个叶子结点求其解Huffman编码
int start = n - 1;
int child = i;
int p = HT[i].parent;
while (p != 0) {//某个Huffman编码
start–;
if (HT[p].lchild == child) {
cd[start] = ‘0’;
}
else {
cd[start] = ‘1’;
}
child = p;
p = HT[p].parent;
}
HC[i] = new char[n - start];
strcpy(HC[i], &cd[start]);
}
free(cd);
}
void CreateHuffmanCoding(HuffmanTree HT, HuffmanCodeTable HC, char text[], char*& encode_text) {//哈夫曼编码文本
int text_len = strlen(text);
encode_text = new char[text_len * length];//存储编码之后的文本
int start = 0;//每个字母编码的起始位置
for (int i = 0; i < text_len; i++) {
char c = text[i];
int index = c - 'a' + 1;//当前字母在哈夫曼表里的位置
char* huffman_code = HC[index];
strcpy(encode_text + start, huffman_code);
start += strlen(huffman_code);
}
}
void CreateHuffmandeCoding(HuffmanTree HT, HuffmanCodeTable HC, char text2[], char*& decode_text) {//哈夫曼译码文本
int root = 1;
while (HT[root].parent != 0) {//从头结点开始译码
root++;
}
int decode_len = strlen(text2);
decode_text = new char[decode_len * length];//存储编码之后的文本
int n = 0;
int j = 0;
while (j < decode_len) {
int p = root;
while (HT[p].lchild != 0 || HT[p].rchild != 0) {//如果不是叶子结点则continue
char code = text2[j];
j++;
if (code == ‘0’) {
p = HT[p].lchild;
}
else {
p = HT[p].rchild;
}
}
decode_text[n] = ‘a’ + p - 1;//找到了该字符后储存进译码数组内
n++;
}
decode_text[n] = ‘\0’;
}
void menu()
{
system(“color 9”);
printf("\n\n\n\n\n");
printf("\t\t\t\t =================================================\n");
printf("\t\t\t\t|| *哈夫曼压缩文件原理 ||\n");
printf("\t\t\t\t|| 1.创建哈夫曼树 ||\n");
printf("\t\t\t\t|| 2.生成字母码表 ||\n");
printf("\t\t\t\t|| 3.文件编码 ||\n");
printf("\t\t\t\t|| 4.文件译码 ||\n");
printf("\t\t\t\t|| 5.退出 ||\n");
printf("\t\t\t\t =================================================\n");
}
int main()
{
while (1)
{
menu();
int x;
int flag = 1;
printf("\n");
int choose;
int c;
printf("\n");
printf(“请选择你要进行的操作(1-7): “);
scanf(”%d”, &choose);
switch (choose)
{
case 1: {system(“cls”);
system(“color 2”);
printf(“根据使用单词的频率设计自己的专属权重:\n\n”);
for (c = 0; c < 26; c++) {
printf(“字母%c的权重为:”, alphabet[c]);
scanf("%d", &weights[c]);
}
HuffmanTree HT;
CreateHuffmanTree(HT, weights, length);
for (int a = 1; a <= 2 * length - 1; a++) {
HTNode node = HT[a];
printf(“第%d个结点的权重为\t%d\t双亲为\t%d\t左孩子为\t%d\t右孩子为\t%d\t\n”, a, node.weight, node.parent, node.lchild, node.rchild);
}
printf(“创建哈夫曼树成功 “);
system(“pause”); system(“cls”);
}break;
case 2: { system(“cls”);
system(“color 2”);
HuffmanTree HT;
CreateHuffmanTree(HT, weights, length);
HuffmanCodeTable hct;
CreateHuffmanCode(HT, hct, length);
for (int i = 1; i <= length; i++) {
printf(”【%d】个结点的字母\t%c\t为编码为\t%s\t\n”, i, alphabet[i - 1], hct[i]);
}
system(“pause”); system(“cls”); }
break;
case 3: {
system(“cls”);
system(“color 2”);
char text[length];
getchar();
printf(“输入单词:”);
gets(text);
printf("\n");
HuffmanTree HT;
CreateHuffmanTree(HT, weights, length);
HuffmanCodeTable hct;
CreateHuffmanCode(HT, hct, length);
for (int i = 1; i <= length; i++) {
printf("【%d】个结点的字母\t%c\t为编码为\t%s\t\n", i, alphabet[i - 1], hct[i]);
}
char* encode_text;
CreateHuffmanCoding(HT, hct, text, encode_text);
printf(“编码完成,文本为%s:”, encode_text);
system(“pause”); system(“cls”);
}
break;
case 4: {
system(“cls”);
system(“color 2”);
char text2[N];
getchar();
printf(“输入编码:”);
gets(text2);
printf("\n");
HuffmanTree HT;
CreateHuffmanTree(HT, weights, length);
HuffmanCodeTable hct;
CreateHuffmanCode(HT, hct, length);
for (int i = 1; i <= length; i++) {
printf("【%d】个结点的字母\t%c\t为编码为\t%s\t\n", i, alphabet[i - 1], hct[i]);
}
char* decode_text;
CreateHuffmandeCoding(HT, hct, text2, decode_text);
printf(“译码完成,文本为%s:”, decode_text);
system(“pause”); system(“cls”);
} break;
case 5: { system(“cls”);
system(“color 2”);
printf("\n\n");
printf(“是否确定退出1.是 2.否 “);
scanf(”%d”, &x);
if (x == 1)
flag = 0;
else
flag = 1;
break; }
default:
printf(“输入不合法,请重新输入!”);
continue;
}
if (flag == 0)
break;
}
return 0;
}