数据结构实验四-赫夫曼编码
2013-11-24 20:49
267 查看
#include <stdio.h> #include <stdlib.h> #include <string.h> ////////////////////////////////////////////////////////////////////////////// /*定义赫夫曼树结点的结构体变量,存放结点的权值、字符、双亲、坐孩子和右孩子*/ typedef struct{ int weight; char ch; //增加一个域用于存放该节点的字符 int parent, lchild, rchild; }HTNode, *HuffmanTree; typedef char **HuffmanCode; //指向赫夫曼编码的指针 ////////////////////////////////////////////////////////////////////////////// /*本程序用到的函数原型*/ void welcome(); //打印操作选择界面 void HuffmanCoding(HuffmanTree &, char *, int *, int);//建立赫夫曼树的算法 void select(HuffmanTree HT, int j, int *s1, int *s2); //从目前已建好的赫夫曼树中选择parent为0且weight最小的两个结点 void Init(); //输入n个字符及其对应的权值,根据权值建立哈夫曼树 void Coding(); //编码 void Decoding(); //译码 void Print_code(); //打印译码好的代码文件 void Print_tree(); //以凹凸表形式打印哈夫曼树 int Read_tree(HuffmanTree &HT); //从文件中读入赫夫曼树 void find(HuffmanTree &HT, char *code, char *text, int i, int m);//译码时根据01字符串寻找相应叶子节点的递归算法 void Convert_tree(unsigned char T[100][100], int s, int *i, int j);//将内存中的赫夫曼树转换成凹凸表形式的赫夫曼树 HuffmanTree HT; //全局变量,指向存放赫夫曼树的存储空间 int n = 0; //全局变量,存放赫夫曼树叶子结点的数目 int main() { char select; while (1) { welcome(); scanf("%c", &select); switch (select) { case 'i': case 'I':Init(); break; case 'c': case 'C':Coding(); break; case 'd': case 'D':Decoding(); break; case 'p': case 'P':Print_code(); break; case 't': case 'T':Print_tree(); break; case 'e': case 'E':exit(1); default:printf("Input error!\n"); } getchar(); } return 0; } void welcome() //打印操作选择界面 { printf("*-----------------------------------------------------*\n"); printf("| What do you want to do? |\n"); printf("|-----------------------------------------------------|\n"); printf("| |\n"); printf("| I--------------------------Init the Huffman tree. |\n"); printf("| C--------------------------Code your file. |\n"); printf("| D--------------------------Decode the code. |\n"); printf("| P--------------------------Print the codefile. |\n"); printf("| T--------------------------Print the Huffman tree. |\n"); printf("| |\n"); printf("*-----------------------------------------------------*\n"); } ////////////////////////////////////////////////////////////////////////////////////// /*初始化函数,输入n个字符及其对应的权值,根据权值建立哈夫曼树,并将其存于文件hfmtree中*/ void Init() { FILE *fp; int i, n, w[52]; //w数组存放n个字符的权值 char character[52]; //存放n个字符 printf("\n输入字符个数 n:"); scanf("%d", &n); //输入字符集大小 printf("输入%d个字符及其对应的权值:\n", n); for (i = 0; i < n; i++) { char b = getchar(); scanf("%c", &character[i]); scanf("%d", &w[i]); //输入n个字符和对应的权值 } HuffmanCoding(HT, character, w, n); //建立赫夫曼树 if ((fp = fopen("hfmtree.txt", "w")) == NULL) printf("Open file hfmtree.txt error!\n"); for (i = 1; i <= 2 * n - 1; i++) { if (fwrite(&HT[i], sizeof(HTNode), 1, fp) != 1) //将建立的赫夫曼树存入文件hfmtree.txt中 printf("File write error!\n"); } printf("\n建立赫夫曼树成功,已将其存于文件hfmtree.txt中\n"); fclose(fp); } /////////////////////////////////////////////////////////////////////////////////// //////建立赫夫曼树的算法/////////////////////////////////////////////////////////// void HuffmanCoding(HuffmanTree &HT, char *character, int *w, int n) { int m, i, s1, s2; HuffmanTree p; if (n <= 1) return; m = 2 * n - 1; HT = (HuffmanTree) malloc((m + 1)*sizeof(HTNode)); for (p = HT + 1, i = 1; i <= n; ++i, ++p, ++character, ++w) { p->ch = *character; p->weight = *w; p->parent = 0; p->lchild = 0; p->rchild = 0; } for (; i <= m; ++i, ++p) { p->ch = 0; p->weight = 0; p->parent = 0; p->lchild = 0; p->rchild = 0; } for (i = n + 1; i <= m; ++i) { select(HT, i - 1, &s1, &s2); HT[s1].parent = i; HT[s2].parent = i; HT[i].lchild = s1; HT[i].rchild = s2; HT[i].weight = HT[s1].weight + HT[s2].weight; } } /////////////////////////////////////////////////////////////////////////////// /*从HT[1]到HT[j]中选择parent为0且weight最小的两个结点,用s1和s2返回其序号*/ void select(HuffmanTree HT, int j, int *s1, int *s2) { int i; //找weight最小的结点 for (i = 1; i <= j; i++) if (HT[i].parent == 0) { *s1 = i; break; } for (; i <= j; i++) if ((HT[i].parent == 0) && (HT[i].weight < HT[*s1].weight)) *s1 = i; HT[*s1].parent = 1; //找weight次小的结点 for (i = 1; i <= j; i++) if (HT[i].parent == 0) { *s2 = i; break; } for (; i <= j; i++) if ((HT[i].parent == 0) && (i != *s1) && (HT[i].weight < HT[*s2].weight)) *s2 = i; } /////////////////////////////////////////////////////////////////////////////// /*对文件tobetrans中的正文进行编码,然后将结果存入文件codefile中*/ void Coding() { FILE *fp, *fw; int i, f, c, start; char *cd; HuffmanCode HC; if (n == 0) n = Read_tree(HT);//从文件hfmtree.txt中读入赫夫曼树,返回叶子结点数 /////以下程序段求赫夫曼树中各叶子节点的字符对应的的编码,并存于HC指向的空间中 { HC = (HuffmanCode) malloc((n + 1)*sizeof(char*) ); cd = (char *) malloc(n*sizeof(char) ); cd[n - 1] = '\0'; for (i = 1; i <= n; ++i) { start = n - 1; for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent) if (HT[f].lchild == c) cd[--start] = '0'; else cd[--start] = '1'; HC[i] = (char *) malloc((n - start)*sizeof(char) ); strcpy(HC[i], &cd[start]); } free(cd); } ///////////////////////////////////////////////////////////////////////////////////// if ((fp = fopen("tobetrans.txt", "rb")) == NULL) printf("Open file tobetrans.txt error!\n"); if ((fw = fopen("codefile.txt", "wb+")) == NULL) printf("Open file codefile.txt error!\n"); char temp; fscanf(fp, "%c", &temp); //从文件读入第一个字符 while (!feof(fp)) { for (i = 1; i <= n; i++) if (HT[i].ch == temp) break; //在赫夫曼树中查找字符所在的位置 for (int r = 0; HC[i][r] != '\0'; r++) //将字符对应的编码存入文件 fputc(HC[i][r], fw); fscanf(fp, "%c", &temp); //从文件读入下一个字符 } fclose(fw); fclose(fp); printf("\n对文件hfmtree.txt编码成功,结果已存入codefile.txt中。\n\n"); } ///////////////////////////////////////////////////////////////////////// /*将文件codefile中的代码进行译码,结果存入文件textfile中*/ void Decoding() { FILE *fp, *fw; int m, i; char *code, *text, *p; if (n == 0) n = Read_tree(HT);//从文件hfmtree.txt中读入赫夫曼树,返回叶子结点数 if ((fp = fopen("codefile.txt", "rb")) == NULL) printf("Open file codefile.txt error!\n"); if ((fw = fopen("textfile.txt", "wb+")) == NULL) printf("Open file textfile.txt error!\n"); code = (char *) malloc(sizeof(char) ); fscanf(fp, "%c", code); //从文件读入一个字符 for (i = 1; !feof(fp); i++) { code = (char *) realloc(code, (i + 1)*sizeof(char) ); //增加空间 fscanf(fp, "%c", &code[i]); //从文件读入下一个字符 } code[i - 1] = '\0'; /////////到此codefile.txt文件中的字符已全部读入,存放在code数组中 text = (char *) malloc(100 * sizeof(char) ); p = text; m = 2 * n - 1; if (*code == '0') find(HT, code, text, HT[m].lchild, m); //从根节点的左子树去找 else find(HT, code, text, HT[m].rchild, m); //从根节点的右子树去找 for (i = 0; p[i] != '\0'; i++) //把译码好的字符存入文件textfile.txt中 fputc(p[i], fw); fclose(fp); fclose(fw); printf("\n对codefile.txt文件译码成功,结果已存入textfile.txt文件。\n\n"); } ////////////////////////////////////////////////////////////////////////////////////////////////////// /*将文件codefi1e以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件codeprint中。*/ void Print_code() { FILE *fp, *fw; char temp; int i; if ((fp = fopen("codefile.txt", "rb")) == NULL) printf("Open file codefile.txt error!\n"); if ((fw = fopen("codeprint.txt", "wb+")) == NULL) printf("Open file codeprint.txt error!\n"); printf("\n文件codefi1e以紧凑格式显示如下:\n"); fscanf(fp, "%c", &temp); //从文件读入一个字符 for (i = 1; !feof(fp); i++) { printf("%c", temp); if (i % 50 == 0) printf("\n"); fputc(temp, fw); //将该字符存入文件codeprint.txt中 fscanf(fp, "%c", &temp); //从文件读入一个字符 } printf("\n\n此字符形式的编码已写入文件codeprint.txt中.\n\n"); fclose(fp); fclose(fw); } ////////////////////////////////////////////////////////////////////////////////////////////////// /*将已在内存中的哈夫曼树以凹凸表形式显示在屏幕上,同时将此字符形式的哈夫曼树写入文件treeprint中。*/ void Print_tree() { unsigned char T[100][100]; int i, j, m = 0; FILE *fp; if (n == 0) n = Read_tree(HT);//从文件hfmtree.txt中读入赫夫曼树,返回叶子结点数 Convert_tree(T, 0, &m, 2 * n - 1); //将内存中的赫夫曼树转换成凹凸表形式的树,存于数组T中 if ((fp = fopen("treeprint.txt", "wb+")) == NULL) printf("Open file treeprint.txt error!\n"); printf("\n以凹凸表形式打印已建好的赫夫曼树:\n"); for (i = 1; i <= 2 * n - 1; i++) { for (j = 0; T[i][j] != 0; j++) { if (T[i][j] == ' ') { printf(" "); fputc(T[i][j], fp); } else { printf("%d", T[i][j]); fprintf(fp, "%d\n", T[i][j]); } } printf("\n"); } fclose(fp); printf("\n此字符形式的哈夫曼树已写入文件treeprint.txt中.\n\n"); } ////////////////////////////////////////////////////////////////////////////////// /*从文件hfmtree.txt中读入赫夫曼树,返回叶子节点数*/ int Read_tree(HuffmanTree &HT) { FILE *fp; int i, n; HT = (HuffmanTree) malloc(sizeof(HTNode)); if ((fp = fopen("hfmtree.txt", "r")) == NULL) printf("Open file hfmtree.txt error!\n"); for (i = 1; !feof(fp); i++) { HT = (HuffmanTree) realloc(HT, (i + 1)*sizeof(HTNode)); //增加空间 fread(&HT[i], sizeof(HTNode), 1, fp); //读入一个节点信息 } fclose(fp); n = (i - 1) / 2; return n; } //////////////////////////////////////////////////////////////// /*译码时根据01字符串寻找相应叶子节点的递归算法*/ void find(HuffmanTree &HT, char *code, char *text, int i, int m) { if (*code != '\0') //若译码未结束 { code++; if (HT[i].lchild == 0 && HT[i].rchild == 0) //若找到叶子节点 { *text = HT[i].ch; //将叶子节点的字符存入text中 text++; if ((*code == '0')) find(HT, code, text, HT[m].lchild, m); //继续从根节点的左子树找 else find(HT, code, text, HT[m].rchild, m); //继续从根节点的右子树找 } else //如果不是叶子节点 if (*code == '0') find(HT, code, text, HT[i].lchild, m); //从该节点的左子树去找 else find(HT, code, text, HT[i].rch ------------------ild, m); //从该节点的右子树去找 } else *text = '\0'; //译码结束 } //////////////////////////////////////////////////////////////////////// /*将内存中的赫夫曼树转换成凹凸表形式的赫夫曼树*/ void Convert_tree(unsigned char T[100][100], int s, int *i, int j) { int k, l; l = ++(*i); for (k = 0; k < s; k++) T[l][k] = ' '; T[l][k] = HT[j].weight; if (HT[j].lchild) Convert_tree(T, s + 1, i, HT[j].lchild); if (HT[j].rchild) Convert_tree(T, s + 1, i, HT[j].rchild); T[l][++k] = '\0'; }
相关文章推荐
- 算法之赫夫曼编码
- 赫夫曼编码
- 数据结构 二叉树应用:赫夫曼编码一
- 赫夫曼树、赫夫曼编码和JAVA实现
- 求赫夫曼编码的算法
- 数据结构(c)——赫夫曼树与赫夫曼编码
- 赫夫曼编码
- 数据结构实验四 栈和队列
- 赫夫曼编码
- 赫夫曼编码
- 数据结构 二叉树应用:赫夫曼编码二
- 赫夫曼编码(优先队列实现)
- 已知某系统在通信联络中只可能出现8种字符,其概率分别为0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11,试编写算法求其赫夫曼编码。
- 数据结构实验四 图的有关操作
- 赫夫曼编码
- 赫夫曼编码
- 赫夫曼编码课设
- Hnust 1071 赫夫曼编码
- 算法导论第16章 构造赫夫曼编码
- 算法导论贪心算法-构造赫夫曼编码