#include<iostream> #include<string> using namespace std; int ABC[104] = { 0 }; //每个字符 权重初始为0 前大后小 int n = 0; bool flag[104] = { false }; //已经处理过 初始false为未处理 char text[10000]; //用text数组将a.txt里面的内容存储 char txt[10000]; //尽可能的大 否则二进制编码越界 int haffman[52][50] = {-1}; FILE *p; int h = 0; //作为全局变量 作用于反编码过程 记录数组下标 struct node { int data; //仍然以数组的下标表示 字符abc int rchild = -1; //右子树 int lchild = -1; //左子树 }nodetree[103]; //寻找数组中最小的值 返回下标 int findmin() { int i = 0; int j = 0; int weight = 0; while (!flag[i]) i++; j = i; weight = ABC[i]; for (; i < 104; i++) { if (flag[i] == true && weight > ABC[i]) //找出字幕出现次数大于0 且最小的 { weight = ABC[i]; j = i; } } flag[j] = false; //找出的最小值下次不再参与 return j; } void creat() { for (int i = 0; i < 52+n-1; i++) { nodetree[i].data = i; } //cout << "最小值排序 :" << endl; for (int i = 52; i <52+n-1; i++) { int a = findmin(); int b = findmin(); //cout << a <<" "<< ABC[a] << endl << b <<" "<<ABC[b] << endl; //cout << char(a + 97-26) << endl; //cout << char(b + 97-26) << endl; nodetree[i].lchild = a; nodetree[i].rchild = b; ABC[i] = ABC[a] + ABC[b]; flag[i] = true; } cout << endl; //for (int i = 52; i < 52 + n - 1; i++) //{ // cout << nodetree[i].data << " " << nodetree[i].lchild << "," << nodetree[i].rchild << endl; //} } int asc[50]; //用以暂时存放haffman编码 int j = -1; //j不会变化 void visittree(node tree) { if (tree.lchild == -1 && tree.rchild == -1) //叶子节点储存字母 { int i = 0; if (tree.data < 26) cout << char(65 + tree.data) << "编码:"; else cout << char(tree.data + 97 - 26) << "编码:"; while (asc[i] != -1) { haffman[tree.data][i] = asc[i]; cout << asc[i++]; } cout << endl ; return; } j++; asc[j] = 0; visittree(nodetree[tree.lchild]); asc[j] = 1; visittree(nodetree[tree.rchild]); asc[j] = -1; j--; } //输入根节点与数组下标 返回数组下标 haffman反编码 int decode(node tree,int i) { if (tree.lchild == -1 && tree.rchild == -1) { if(tree.data<26) fprintf(p, "%c", tree.data +65); else fprintf(p, "%c", tree.data + 97 - 26); return h; } h++; if (text[i] == '0') decode(nodetree[tree.lchild],i+1); else decode(nodetree[tree.rchild],i+1); } int main() { //进行初始化 memset(flag, false, sizeof(flag)); memset(asc, -1, sizeof(asc)); memset(haffman, -1, sizeof(haffman)); //读取已存在的文件a.txt 并把文件内容放到text数组与txt数组中 方便操作 char ch; int i = 0; p = fopen("E:\\a.txt", "r"); if (p == NULL) { printf("failed to open file. "); exit(1); } cout << "原文中含有的英文字母是:" << endl; while ((ch = getc(p)) != EOF) { if (ch >= 65 && ch <= 90||ch>=97&&ch<=122) { txt[i] = ch; text[i++] = ch; cout << ch; } } //text[i] = '\0'; //txt[i] = '\0'; fclose(p); //输出文件中a-z,A—Z的出现的次数 以及总共出现的字母数 cout << endl; i = 0; while (text[i] != '\0')//将字mu出现的次数记录作为权值写到数组ABC { if (text[i] <= 90) ABC[text[i++] - 65]++; else ABC[text[i++] - 97 + 26]++; } for (i = 0; i < 26; i++) { cout << "字母:" << char(i + 65) << "次数:" << ABC[i] << endl; } for (; i < 52; i++) { cout << "字母:" << char(i + 97-26) << "次数:" << ABC[i] << endl; } for (i = 0; i < 52; i++) { if (ABC[i]!=0) { n++; flag[i] = true; } } cout <<endl<< "总共的字母数量是n:" << n << endl; //创建haffman树 nodetree[n-2+52]作为根节点 //visittree函数将遍历所有叶子节点 并把得到的haffman编码写入二维数组haffman中 creat(); visittree(nodetree[n - 2+52]); //输出字母的haffman编码 cout << endl << endl << endl; for (i = 0,j=0; i < 52; i++) { if (ABC[i] != 0) if (i < 26) { cout << char(65 + i) << "编码:"; while (haffman[i][j] != -1) cout << haffman[i][j++]; cout << endl; } else { cout << char(i + 97-26) << "编码:"; while (haffman[i][j] != -1) cout << haffman[i][j++]; cout << endl; } j = 0; } //创建b.txt 将text数组中的字母编码后写入 i = 0; p = fopen("E:\\b.txt", "w"); while ((ch = text[i++])!='\0') { if (ch < 91) { j = 0; while (haffman[ch - 65][j] != -1) fprintf(p, "%d", haffman[ch - 65][j++]); } else { j = 0; while (haffman[ch - 97+26][j] != -1) fprintf(p, "%d", haffman[ch - 97+26][j++]); } } fclose(p); //输出b.txt中的内容 并存到text数组中 p = fopen("E:\\b.txt", "r"); fscanf(p, "%s", text); printf("b.txt: %s\n", text); fclose(p); //创建c.txt 对text进行反编码写c.txt p = fopen("E:\\c.txt", "w"); while (text[h] != '\0') { decode(nodetree[52 + n - 2], h); } fclose(p); cout << endl; //输出c.txt文件里面的内容 对比a.txt p = fopen("E:\\c.txt", "r"); fscanf(p, "%s", text); printf("c.txt: %s\n", text); fclose(p); cout << endl; printf("a.txt: %s\n", txt); cout << endl; //比较a.txt与c.txt的内容 if (strcmp(text, txt) == 0) cout << "a.txt与c.txt相等,编码成功" << endl; else cout << "编码失败" << endl; getchar(); return 0; }