#include <bits/stdc++.h>
#define
using namespace std;
typedef struct {
char ch;
int weight;
int parent, left, right;
}HTNode, *HuffmanTree;
typedef char ** HuffmanCode;
void Select (HuffmanTree HT, int end, int *s1, int *s2);
void CreateHuffmanTree (HuffmanTree *HT, int *w, int n);
void HuffmanCoding (HuffmanTree HT, HuffmanCode * HC, int n);
void PrintHuffmanTreeCode (HuffmanTree HT, HuffmanCode htable, int n);
void CodeArticle (HuffmanTree HT, HuffmanCode HC, int n);
void DecodeArticle(HuffmanTree HT, HuffmanCode HC, int n);
void PreOrder (HuffmanTree HT, int n);
void LevelOrder (HuffmanTree HT, int n);
void InOrder (HuffmanTree HT, int n);
void PostOrder (HuffmanTree HT, int n);
void PrintPersent (HuffmanTree HT, HuffmanCode HC, int n);
int main () {
int w[Max] ={0}, n = 0;
FILE *fp;
if (!(fp = fopen("article.txt", "r"))) {
puts ("打开失败");
exit(0);
}
char ch;
while (fscanf (fp, "%c", &ch) != EOF) {
// if (!isalpha(ch)) continue;
if (w[ch] == 0) n ++;
w[ch] ++;
}
fclose(fp);
HuffmanTree htree;
HuffmanCode htable;
CreateHuffmanTree(&htree, w, n);
HuffmanCoding(htree, &htable, n);
PrintHuffmanTreeCode(htree, htable, n);
CodeArticle (htree, htable, n);
DecodeArticle(htree, htable, n);
PrintPersent(htree, htable, n);
return 0;
}
void Select (HuffmanTree HT, int end, int *s1, int *s2) {
int min1, min2;
int i = 1;
while(HT[i].parent != 0 && i <= end) i ++;
min1 = HT[i].weight, *s1 = i;
i ++;
while(HT[i].parent != 0 && i <= end) i ++;
if (HT[i].weight < min1 ) {
min2 = min1;
*s2 = *s1;
min1 = HT[i].weight;
*s1 = i;
}
else {
min2 = HT[i].weight, *s2 = i;
}
for (int j = i+ 1; j <= end; j ++) {
if (HT[j].parent != 0) continue;
if (HT[j].weight < min1) {
min2 = min1, *s2 = *s1;
min1 = HT[j].weight, *s1 = j;
}
else if (HT[j].weight < min2) {
min2 = HT[j].weight, *s2 = j;
}
}
}
void CreateHuffmanTree (HuffmanTree *HT, int *w, int n) {
if (n <= 1) return ;
int m = 2 *n -1;
*HT = (HuffmanTree)malloc(sizeof (HTNode) * (m + 1));
HuffmanTree p = *HT;
int cnt = 0;
for (int i = 0; i <= 256; i ++) {
if (w[i]) {
(*HT)[++cnt].ch = (char)i;
(*HT)[cnt].weight = w[i];
(*HT)[cnt].parent = (*HT)[cnt].left = (*HT)[cnt].right = 0;
}
}
for (int i = n + 1; i <= m; i ++) {
(p +i)->ch = ' ';
(p +i)->weight = (p + i)->parent = (p + i)->left = (p +i)->right = 0;
}
for (int i = n + 1; i <= m; i ++) {
int s1, s2;
Select (*HT, i - 1, &s1, &s2);
(*HT)[s1].parent = (*HT)[s2].parent = i;
(*HT)[i].weight = (*HT)[s1].weight + (*HT)[s2].weight;
(*HT)[i].ch = '#';
(*HT)[i].left = s1;
(*HT)[i].right = s2;
}
}
void HuffmanCoding (HuffmanTree HT, HuffmanCode * HC, int n) {
*HC = (HuffmanCode)malloc(sizeof (char *) * (n + 1));
char *cd = (char *)malloc(sizeof (char) * (n +1));
cd[n - 1] = '\0';
for (int i = 1; i <= n; i ++) {
int start = n - 1;
int c = i;
int j = HT[i].parent;
while (j != 0) {
if (HT[j].left == c) cd[--start] = '0';
else if (HT[j].right == c) cd[--start] = '1';
c = j;
j = HT[j].parent;
}
(*HC)[i] = (char *)malloc(sizeof (char) * (n - start));
strcpy ((*HC)[i], &cd[start]);
}
free(cd);
}
void CodeArticle (HuffmanTree HT, HuffmanCode HC, int n) {
FILE * fin, *fout;
if (!(fin = fopen ("Article.txt", "r")) || !(fout = fopen ("CodeArticle.txt", "w"))) {
puts ("打开文件失败");
exit(0);
}
char ch;
while(fscanf (fin, "%c", &ch) != EOF) {
char *str = (char*)malloc(sizeof (char) * (n +2));
for (int i = 1; i <= n; i ++) {
if ((char)HT[i].ch == ch) {
strcpy (str, HC[i]);
break;
}
}
fprintf (fout, "%s", str);
}
fclose(fin);
fclose(fout);
}
void DecodeArticle (HuffmanTree HT, HuffmanCode htable, int n) {
FILE *fin, * fout;
if (!(fin = fopen ("CodeArticle.txt", "r")) || !(fout = fopen ("DecodeArticle.txt", "w"))) {
puts ("打开文件错误");
exit(0);
}
char ch, *str;
str = (char *)malloc(sizeof (char) * n);
int cnt = 0, p = 2 * n - 1;
while (fscanf (fin, "%c", &ch) != EOF) {
if (ch == '0') p = HT[p].left;
else p = HT[p].right;
if (HT[p].ch != '#') {
fprintf (fout, "%c", HT[p].ch);
p = 2 * n - 1;
}
}
fclose(fin);
fclose(fout);
}
void PrintHuffmanTreeCode (HuffmanTree HT, HuffmanCode htable, int n) {
printf ("Huffman cod: \n");
for (int i = 1; i <= n; i ++) printf ("%c : %d code = %s\n",HT[i].ch, HT[i].weight, htable[i]);
}
//各种遍历
void PreOrder(HuffmanTree HT, int p) {
cout << HT[p].ch;
if(HT[p].left) PreOrder(HT, HT[p].left);
if (HT[p].right) PreOrder(HT, HT[p].right);
}
void InOrder(HuffmanTree HT, int p) {
if (HT[p].left) InOrder(HT, HT[p].left);
cout << HT[p].ch;
if (HT[p].right) InOrder(HT, HT[p].right);
}
void PostOrder (HuffmanTree HT, int p) {
if (HT[p].left) PostOrder(HT, HT[p].left);
if (HT[p].right) PostOrder(HT, HT[p].right);
cout << HT[p].ch;
}
void LevelOrder(HuffmanTree HT, int p) {
queue<int> q;
q.push(p);
while(q.size()) {
int t = q.front(); q.pop();
cout << HT[t].ch;
if (HT[t].left) q.push(HT[t].left);
if (HT[t].right) q.push(HT[t].right);
}
}
void PrintPersent (HuffmanTree HT, HuffmanCode HC, int n) {
int length[n + 1];
double w[n + 1], sum = 0, bit = 0;
for (int i = 1; i <= n; i ++) length[i] = strlen (HC[i]), sum += HT[i].weight;
for (int i = 1; i<= n; i ++) w[i] = HT[i].weight / sum;
int m = n;
while (m) m /= 2, bit ++;
if (m) bit ++;
double up = 0;
for (int i = 1; i <= n; i ++) {
up += w[i] * length[i];
}
printf ("压缩比: %.4lf%\n", (1 - up / bit) * 100);
}
















