Huffman 编码


具体原理及定义请百度,下面直接进行实现。具体实现过程是: 统计若干字符出现的频率,将其按频率(权重)升序存放进队列中,每次从队列中取两个结点合成一颗二叉树,这两个结点的根节点是取出来两个结点的字符的权重和,并且将新的结点放入队列中,满足队列依旧是升序排列,一直持续直到队列中仅剩最后一个结点,此时这个结点就是 Human 树的根节点,构成的树也叫最优二叉树


源代码

下面将分为两个文件,作用分别是 Huffman 编码以及解码,不再模拟传输过程,仅仅是简单模拟数据压缩以及恢复过程。
由于分为了两个文件,而两个文件都需要得到每个字符的Huffman编码(或者说Huffman树),因此两个文件构造Huffman树的过程是一样的,并且都读取同一个文件的数据来生成Huffman树

encode.c

/*** Huffman 编码的实现*/#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define FILEINPUTSTRING "inputString.txt"
#define FILEENCODESTRING "encodeString.txt"
#define FILEENCODING "encoding.txt"/*** Huffman 树的结点* @param mCharacter 要编码的单个字符*/
typedef struct nodeTree {char mCharacter;struct nodeTree* mLeft;struct nodeTree* mRight;
}NodeTree, *LPNodeTree;/*** 树* 指向树的根结点的指针*/
typedef struct {LPNodeTree root;
}Tree, *LPTree;/*** 队列结点* 根据分析可知构成 Huffman 树要通过一个单调优先队列来完成* 因为要进行多次插入操作,因此选择链队列,并且由于不像常规的队列一样* 满足头部弹出,尾部进入,因此可不设头尾指针 (其实更像链表) * @param mPriority 权重,即字符出现的次数* @param mTreeNode 树的结点*/
typedef struct nodeQueue {unsigned int mPriority;NodeTree mTreeNode;struct nodeQueue* mNext;
}NodeQueue, *LPNodeQueue;/************************************************************ Huffman 树的构建                                         ** 先将每种字符保存在队列的树结点中,并将权重保存在队列中          ** 再将所有结点按照权重升序插入单调优先队列中                    ***********************************************************//*** 初始化空队列* 将队列创建出来 (空队列),各个成员都赋予初值* @return 队列头结点*/
LPNodeQueue initialQueue() {LPNodeQueue headQueueNode = (LPNodeQueue)malloc(sizeof(NodeQueue));     // 堆区申请队列头结点空间headQueueNode->mNext = NULL;headQueueNode->mPriority = 0;headQueueNode->mTreeNode.mCharacter = 0;headQueueNode->mTreeNode.mLeft = headQueueNode->mTreeNode.mRight = NULL;        // 初始化队列头结点的各个成员return headQueueNode;
}/*** 创建队列的单个结点,并将其成员赋值* @param priority 字符的权重* @param character 被统计的单个字符* @param left 树结点的左孩子* @param right 树结点的右孩子* @return 单个队列结点*/
LPNodeQueue createQueueNode(unsigned int priority, char character, LPNodeTree left, LPNodeTree right) {LPNodeQueue newQueueNode = (LPNodeQueue)malloc(sizeof(NodeQueue));newQueueNode->mNext = NULL;newQueueNode->mPriority = priority;newQueueNode->mTreeNode.mCharacter = character;newQueueNode->mTreeNode.mLeft = left;newQueueNode->mTreeNode.mRight = right;return newQueueNode;
}/*** 创建树结点* @param character 被统计的单个字符* @param left 树结点的左孩子* @param right 树结点的右孩子* @return 树结点*/
LPNodeTree createTreeNode(char character, LPNodeTree left, LPNodeTree right) {LPNodeTree newTreeNode = (LPNodeTree)malloc(sizeof(NodeTree));newTreeNode->mCharacter = character;newTreeNode->mLeft = left;newTreeNode->mRight = right;return newTreeNode;
}/*** 入队列操作,将结点按权重升序插入队列* @param headQueueNode 要插入的队列头结点* @param queueNode 要插入的队列结点*/
void enQueue(LPNodeQueue headQueueNode, LPNodeQueue queueNode) {LPNodeQueue preQueueNode = headQueueNode;   // preQueueNode 一直指向 moveQueueNode 的直接前驱结点LPNodeQueue moveQueueNode = headQueueNode->mNext;   // moveQueueNode 定位为首元结点/*** 队列不为空并且待插入结点的权值大于当前 moveQueueNode 的权值,* 则要将待插入结点往后移动* 最终定位到 preQueueNode 是 moveQUeueNode 的直接前驱结点,此时 moveQUeueNode 所处的位置应该是* 待插入结点的目标位置*/while(moveQueueNode!=NULL && queueNode->mPriority>moveQueueNode->mPriority) {preQueueNode = moveQueueNode;moveQueueNode = moveQueueNode->mNext;}queueNode->mNext = moveQueueNode;preQueueNode->mNext = queueNode;    // 找到定位后将新结点直接插入即可
}/*** 出队列操作,将头结点指向的结点移出队列并返回队列结点元素的树结点* 因为最终是需要使用树结点来构成最优二叉树,而非是队列结点* @param headQueueNode 队列头结点* @return 移出队列结点元素的树结点*/
LPNodeTree deQueue(LPNodeQueue headQueueNode) {// 空队列直接退出LPNodeQueue moveQueueNode = headQueueNode->mNext;if(moveQueueNode == NULL) {printf("QUEUE EMPTY!\n");exit(1);        // 直接中止程序}// 重新构建一个树结点,将移出的队列结点释放LPNodeTree returnTreeNode = createTreeNode(moveQueueNode->mTreeNode.mCharacter, moveQueueNode->mTreeNode.mLeft, moveQueueNode->mTreeNode.mRight);headQueueNode->mNext = moveQueueNode->mNext;    // 移除出队列首元结点moveQueueNode->mNext = NULL;free(moveQueueNode);moveQueueNode = NULL;return returnTreeNode;
}/*** 统计字符串各个字符的权重并构建单调优先队列* @param inputString 待统计的字符串,通过文件得到* @return 单调优先队列的头结点*/
LPNodeQueue getPriorityAndCreateQueue(char* inputString) {/*** 按照 ASCII 码来统计字符,使用哈希表* ASCII 码表上总共有 256 个字符*/unsigned int* priority = (unsigned int*)calloc(256, sizeof(unsigned int));for(int i = 0; inputString[i] != '\0'; ++i) {priority[inputString[i]]++;}// 创建队列LPNodeQueue headQueueNode = initialQueue();for(int i = 0; i < 256; ++i) {if(priority[i] > 0) {   // 字符数量大于 0 的才入队列LPNodeQueue newQueueNode = createQueueNode(priority[i], (char)i, NULL, NULL); // 创建队列结点,此时树结点的左右子树都是空enQueue(headQueueNode, newQueueNode);       // 将队列结点插入队列}}free(priority);return headQueueNode;
}/*** 创建 Huffman树* @param inputString 构建树的字符串,由文件得到* @return Huffman 指向 Huffman 树的根节点的指针*/
LPTree createHuffmanTree(char* inputString) {if(inputString == NULL) {printf("INPUTSTRING EMPTY!\n");exit(1);}LPNodeQueue headQueueNode = getPriorityAndCreateQueue(inputString); // 得到单调优先队列if(headQueueNode->mNext == NULL) {  // 队列为空printf("QUEUE EMPTY!\n");exit(1);}/*** 取出队列两个结点合并成为一个根结点后在插入队列,* 直到队列中只剩一个结点*/while(headQueueNode->mNext->mNext != NULL) {unsigned int priority = headQueueNode->mNext->mPriority +headQueueNode->mNext->mNext->mPriority; // 先得到将要弹出的的两个结点的权重之和LPNodeTree left = deQueue(headQueueNode);LPNodeTree right = deQueue(headQueueNode);LPNodeQueue newQueueNode = createQueueNode(priority, '0', left, right);   // 创建新的队列结点,此时有左右孩子了,而字符可以随意给一个enQueue(headQueueNode, newQueueNode);}/*** 创建树指针,指向 Huffman 树的根结点*/LPTree huffmanTree = (LPTree)malloc(sizeof(Tree));LPNodeTree newTreeNode = createTreeNode(headQueueNode->mNext->mTreeNode.mCharacter, headQueueNode->mNext->mTreeNode.mLeft, headQueueNode->mNext->mTreeNode.mRight);// 销毁最后一个队列结点以及头结点LPNodeQueue firstQueueNode =  headQueueNode->mNext;headQueueNode->mNext = NULL;free(firstQueueNode); firstQueueNode = NULL;free(headQueueNode); headQueueNode = NULL;huffmanTree->root = newTreeNode;return huffmanTree;
}/*************************************************   到此 Huffman 树已经构建完成,下面可以简单测试一下 ********************************//*** 树的前序遍历*/
void preprint(LPNodeTree root) {if(root != NULL) {printf("%c ", root->mCharacter);preprint(root->mLeft);preprint(root->mRight);}
}/*** 树的中序遍历*/
void midprint(LPNodeTree root) {if(root != NULL) {midprint(root->mLeft);printf("%c ", root->mCharacter);midprint(root->mRight);}
}void testHuffmanTree() {/*** 输入的字符串定为 "aaaaabbbbcccddeffffff",即 5 个 a,4 个 b,3 个 c, 2 个 d,1 个 e 以及 6 个 f* 这样简单的字符经过人工计算得到的 Huffman 树的* 前序遍历应该为 "0 0 b a 0 0 0 e d c f"* 中序遍历应该为 "b 0 a 0 e 0 d 0 c 0 f"* 出现 0 是因为在 createHuffmanTree() 函数中创建新的队列结点时给的任意字符为 '0'* 经验证确实如此*/char* inputString = "aaaaabbbbcccddeffffff";LPTree huffmanTree = createHuffmanTree(inputString);preprint(huffmanTree->root);printf("\n");midprint(huffmanTree->root);
}/*************************************************************************** Huffman 树创建完成之后就可以提取 Huffman 编码表了,可以有很多方法              ** 比如链表链接,但是对于编码表来说,查找肯定是主要操作,所以选择用查找速度更快的      ** 哈希表,通过遍历 Huffman 树,左子树填 0 右子树填 1,最终构成一个完整的编码表     ***************************************************************************//*** 初始化 HushMap,由于 key 值是字符,因此可以直接把字符对应的 ASCII 码作为索引* @return 二维哈希表的首地址,行表示的是每个字符,列表示的是每个字符的二进制编码*/
char** initialHushMapCodingTable() {/*** 由于 ASCII 码中有 256 个字符 (包括不可见字符,因为要用十进制 ASCII 作为索引,* 因此不可见字符虽然不会出现在 inputString 中,但还是需要为他们创建索引),所以* 需要创建 256 个连续空间,用用来保存每一个字符的编码*/char** codingTable = (char**)calloc(256, sizeof(char*));return codingTable;
}/*** 将二进制编码信息录入到编码表中* @param codingTable 待录入信息的 Huffman 编码表* @param code 编码* @param character 编码对应的字符*/
void addCodingToCodingTable(char** codingTable, char* code, char character) {int codeSize = strlen(code);codingTable[character] = (char*)malloc(sizeof(codeSize+1));   // 给要录入信息的字符开辟存储编码的空间strcpy(codingTable[character], code);
}/*** 递归遍历 Huffman 树来得到每个字符的编码,并将其加入编码表* @param root Huffman 树的根结点* @param codingTable Huffman 编码表* @param code 存储当前字符的 Huffman 编码信息* @param k code 当前的长度,也可以说是当前结点所在树的深度*/
void travelHuffmanTree(LPNodeTree root, char** codingTable, char* code, int k) {// 递归出口,当遍历到 Huffman树的叶子节点时,就到达了字符所在的位置,此时 code 中就是编码if(root->mLeft==NULL && root->mRight==NULL) {code[k] = '\0';     // 给编码加上截至符addCodingToCodingTable(codingTable, code, root->mCharacter);    // 加入编码表}if(root->mLeft != NULL) { // 遍历左子树code[k] = '0';  // 左分支填 0travelHuffmanTree(root->mLeft, codingTable, code, k+1);     // 进行递归,k 值要加一}if(root->mRight != NULL) {  // 右子树code[k] = '1';travelHuffmanTree(root->mRight, codingTable, code, k+1);}
}/*** 创建 Huffman 编码表* @param tree Huffman 树指针* @return 完整的编码表首地址*/
char** createHuffmanCodingTable(LPTree tree) {char** codingTable = initialHushMapCodingTable();char* code = (char*)calloc(256, sizeof(char));  // 先给编码开辟足够的空间travelHuffmanTree(tree->root, codingTable, code, 0);    // 从树的根结点 (第 0 层)开始free(code); // 填好表后释放空间return codingTable;
}
/***********************************************  到此 Huffman 编码表也已经创建完成,下面简单测试一下  **********************************//************************************************************************ 输入的字符串还是用之前测试 Huffman 树的数据,即 "aaaaabbbbcccddeffffff",  ** 那么得到的编码表应该如下:                                               ** a 01                                                                ** b 00                                                                ** c 101                                                               ** d 1001                                                              ** e 1000                                                              ** f 11                                                                ** 经验证确实如此                                                        ************************************************************************/void testHuffmanCodingTable() {char* inputString = "aaaaabbbbcccddeffffff";LPTree huffmanTree = createHuffmanTree(inputString);char** codingTable = createHuffmanCodingTable(huffmanTree);for(int i = 0; i < 256; ++i) {if(codingTable[i] != NULL) {printf("%c %s\n", i, codingTable[i]);}}
}
/********************************************   将待编码字符生成二进制编码   *******************************************//*** 将待编码字符生成编码 (这里的字符只能是编码表中出现过的字符)* @param codingTable 完整的编码表* @param  encodeString 待编码字符* @return 所有字符的编码*/
char* encode(char** codingTable, char* encodeString) {char* huffmanCode = (char*)malloc(sizeof(char));huffmanCode[0] = '\0';char* tmp = NULL;int size = 0;for(int i = 0; encodeString[i] != '\0'; ++i) {int size1 = strlen(codingTable[encodeString[i]]);    // 得到当前字符的编码长度size += size1;        // 得到当前已保存的编码的总长度tmp = (char*)realloc(huffmanCode, sizeof(char) * (size+10));       // 重新分配更大的空间if(tmp == NULL) {printf("HUFFMANCODE  REALLOCATE MEMORY FAILD!\n");exit(1);}huffmanCode = tmp;strcat(huffmanCode, codingTable[encodeString[i]]);}return huffmanCode;
}/***************************************************     编码生成之后也可以进行小测试     *********************************//************************************************************************ 生成 Huffman 编码表的字符还是跟前两次测试一样,                           ** 而待编码的字符定为 "dacbfeabe" (只能是编码表中存在的字符),则人工计算结果为   **   d  a   c  b  f    e  a  b    e                                    ** 1001 01 101 00 11 1000 01 00 1000                                   ** 最终结果即为一串上述二进制数字                                           ** 经验证确实如此                                                        ***********************************************************************/void testHuffmanEncode() {char* inputString = "aaaaabbbbcccddeffffff";LPTree huffmanTree = createHuffmanTree(inputString);char** codingTable = createHuffmanCodingTable(huffmanTree);char* encodeString = "dacbfeabe";char* huffmanCode = encode(codingTable, encodeString);printf("%s\n", huffmanCode);
}/**********************************************  至此 encode.c 编码功能已经全部完成    ***************************************************//**************************************************** 文件操作,程序中的 inputString 都应该要从文件中读取   ** 并且生成的编码也要保存到文件中                       ***************************************************//*** 从文件中读出文本,这个文件 (INPUTSTRING)是公共的、构成 Huffman 树的* 字符文件,并不是要编码或者是解码的文件* @return 保存有文本的地址*/
char* getInputString() {FILE* fp = fopen(FILEINPUTSTRING, "r");if(fp == NULL) {printf("%s OPEN FAILD!\n", FILEINPUTSTRING);exit(1);}fseek(fp, 0L, SEEK_END);    // 将光标定位到文件末尾,方便统计文件内字符数量long int size = ftell(fp);if(size == 0) {printf("%s EMPTY!\n", FILEINPUTSTRING);exit(1);}fseek(fp, 0L, SEEK_SET);    // 统计完后将光标重新定位到文件开头char* inputString = (char*)calloc(size+10, sizeof(char));   char ch;for(int i = 0; (ch = fgetc(fp)) != EOF; ++i) {      // 将数据存入 inputStringinputString[i] = ch;inputString[i+1] = '\0';}fclose(fp);return inputString;
}/*** 从文件中读取文本,这个文件 (ENCODE)中是待编码的字符* @return 保存有文本的地址*/
char* getEncodeString() {FILE* fp = fopen(FILEENCODESTRING, "r");if(fp == NULL) {printf("%s OPEN FAILD!\n", FILEENCODESTRING);exit(1);}fseek(fp, 0L, SEEK_END);    // 将光标定位到文件末尾,方便统计文件内字符数量long int size = ftell(fp);if(size == 0) {printf("%s EMPTY!\n", FILEENCODESTRING);exit(1);}fseek(fp, 0L, SEEK_SET);    // 统计完后将光标重新定位到文件开头char* encodeString = (char*)calloc(size+10, sizeof(char));   char ch;for(int i = 0; (ch = fgetc(fp)) != EOF; ++i) {      // 将数据存入 encodeStringencodeString[i] = ch;encodeString[i+1] = '\0';}fclose(fp);return encodeString;
}/*** 将生成的编码写入文件中* @param huffmanCode 二进制编码*/
void putHuffmanCodingInFIle(char* huffmanCode) {FILE* fp = fopen(FILEENCODING, "w+");for(int i = 0; huffmanCode[i] != '\0'; ++i) {fputc(huffmanCode[i], fp);}fclose(fp);
}/***********************************************************  操作流程   *************************************************/
void huffmanEncode() {// 读取 (INPUTSTRING) 文本char* inputString = getInputString();// 构建 Huffman 树LPTree huffmanTree = createHuffmanTree(inputString);// 构建 Huffman 编码表char** huffmanCodingTable = createHuffmanCodingTable(huffmanTree);// 读取 (FILEENCODESTRING) 文本char* encodeString = getEncodeString();// 生成 Huffman 编码char* huffmanCode = encode(huffmanCodingTable, encodeString);// 将 Huffman 编码写入文件 (FILEENCODING)putHuffmanCodingInFIle(huffmanCode);printf("\n\nENCODE SUCCESS!\n\n");
}/************************************************************* main 函数 *******************************************/
int main() {// testHuffmanTree();// testHuffmanCodingTable();// testHuffmanEncode();huffmanEncode();return 0;
}

encode.c 的各个测试结果以及各文件内容及最后的输出文件

  • 哈夫曼树的测试 - - testHuffmanTree() 函数

    与预期结果一致
  • 哈夫曼编码表的测试 - - testHuffmanCodingTable() 函数

    与预期结果一致
  • 哈夫曼编码的测试 - - testHuffmanEncode() 函数

    与预期结果一致
  • 执行结果 - - huffmanEncode() 函数

inputString.txt

文件 inputString.txt 中是几篇高中英语课文(不含中文字符),并随机在文本中插入了键盘上的所有可见字符,保证编码表中包含所有英文可见字符 (大概8632字符)

Festivals and celebrations Festivals and celebrations of all kinds have been held everywhere since ancient times.Most ancient
festivals would celebrate the end of cold weather,planting in spring and harvest in autumn.Sometimes
celebratewould be held after hunters had caught animals.At that time people would starve if food was
difficult to find,especially during the cold winter months.Today's festivals have many origins ,some
religious,some seasonal, and some for special people or events. Festivals of the Dead Some festivals are held to honour the dead or to satisfy the ancestors,who might return either to
help or to do harm.For the Japanese festival.Obon,people should go to clean graves and light incense
in memory of their ancestors.They also light lamps and play music because they think that this will
lead the ancestors back to earth.In Mexico,people celebrate the Day of the Dead in early November.On
this impoutant feast day,people eat food in the shape of skulls and cakes with "bones" on them.They offer
food,flowers and gifts to the dead.The Western holiday Halloween also had its origin in old beliefs about
the return of the spirits of dead people. It is now a children's festival,when they can dress up and to to
their neighbours'homes to ask for sweets.If the neighbours do not give any sweets,the children might play a
trick on them. ` 1 2 3 4 5 6 7 8 9 0 - = Festivals to Honour People Festivals can also be held to honour famous people .The Dragon Boat Festival in China honours the
famous ancient poet,Qu Yuan.In the USA Columbus Day is in memory of the arrival of Christopher Columbus in New
World.India has a national festival on October 2 to honour Mohandas Gandhi,the leader who helped gain India's
independence from Britain. Harvest Festivals Harvest and Thanksgiving festivals can be very happy events.People are grateful because their food is
gathered for the winter and the agricultural work is over.In European countries,people will usually decorate
churches and town halls with flowers and fruit,and will get together to have meals.Some people might win
awards for their farm produce,like the biggest watermelon or the most handsome rooster.China and Japan have
mid-autumn festivals,when people admire the moon and in China,enjoy mooncakes. Spring Festivals The most energetic and important festivals are the ones that look forward to the end of winter and to
the coming of spring.At the Spring Festival in China,people eat dumplings,fish and meat and may give
children lucky money in red paper.There are dragon dances and carnivals,and families celebrate the Lunar
New Year together.Some Western countries have very exciting carnivals,which take place forty days before
Easter,usually in February.These carnivals might include parades,dancing in the streets day and night,loud
music and colourful clothing of all kinds.Easter is an important religious and social festival for
Christians aroud the world.It celebrates the return of Jesus from the dead and the coming of spring and new
life.Japan’s Cherry Blossom Festival happens a little later.The country, covered with cherry tree flowers,
looks as thought it is covered with pink snow. People love to get together to eat , drink and have fun with
each other.Festivals let us enjoy life,be proud of our customs and forget our work for a little while q w e r t y u i o p [ ] \A SAD LOVE STORYLi Fang was heart-broken.It was Valentine's Day and Hu Jin had said she would meet him at the coffee
shop after work. But she didn't turn up. She could be with her friends right now laughing at him.She said
she would be there at seven o'clock, and he thought she would keep her word. He had looked forward to
meeting her all day, and now he was alone with his roses and chocolates, like a fool. Well, he was not
going to hold his breath for her to apologize. He would drown his sadness in coffee. It was obvious that the manager of the coffee shop was waiting for Li Fang to leave-he wiped the tables,
then sat down and turned on the TV-just what Li Fang needed! A sad Chinese story about lost love. a s d f g h j k l ; ' The granddaughter of the Goddess of Heaven visted the earth. Her name was Zhinü,the weaving girl. While
she was on earth she met the herd boy Niulang and they fell in love.("Just like me and Hu Jin,"thought Li Fang.)
They got married secretly, and they were very happy.("We could be like that,"thought Li Fang.)When the Goddess
of Heaven knew that her granddaughter was married to a human, she became very angry and made the weaving girl
return to Heaven.Niulang tried to follow her, but the river of stars,the Milly Way, stopped him.Finding that
Zhinu was heart-broken, her grandmother finally decided to let the couple cross the Milky Way to meet once a
year. Magpies make a bridge of their wings so the couple can cross the river to meet on the seventh day of
the seventh lunar month. People in China hope that the weather will be fine on that day, because if it is
raining, it means that Zhinü is weeping and the couple won't be able to meet. The announcer said,"This is the story of Qiqiao Festival.When foreigners hear about the story, they call
it a Chinese Valentine's story.It's a fine day today, so I hope you can all meet the one you love." z x c v b n m , . / As Li Fang set off for home, he thought,"I guess Hu Jin doesn't love me .I'll just throw these flowers
and chocolates away. I don't want them to remind me of her." So he did. ~ ! @ # $ % ^ & * ( ) _ + As he sadly passed the tea shop on the corner on his way home, he heard a voice calling him. There was Hu Jin
waving at him and calling , "why are you so late?I've been waiting for you for a long time!And I have a gift for you!" What would he do? He had thrown away her Valentine gifts!She would never forgive him. This would not be a happy
Valentine's Day! UNIT2
COME AND EAT HERE (1) Wang Peng sat in his empty restaurant feeling very frustrated. It had been a very strange morning. Usually he
got up early and prepared his menu of barbecued mutton kebabs, roast pork, stir-flied vegetables and fried rice. Q W E R T Y U I O P { } | Then by lunchtime they would all be sold. By now his restaurant ought to be full of people. But not today! Why was that?
What could have happened? He thought of his mutton, beef and bacon cooked in the hottest, finest oil. His cola was sugary
and cold, and his ice cream was made of milk, cream and delicious fruit. "Nothing could be better," he thought. Suddenly
he saw his friend Li Chang hurrying by. "Hello, Lao Li," he called. "Your usual?" But Li Chang seemed not to hear.
What was the matter? Something terrible must have happened if Li Chang was not coming to eat in his restaurant as
he always did. Wang Peng followed Li Chang into a new small restaurant. He saw a sign in the window. Tired of all
that fat? Want to lose weight? Come inside Yong Hui's slimming restaurant. Only slimming foods served here. Make
yourself thin again! Curiosity drove Wang Peng inside. It was full of people. The hostess, a very thin lady, came A S D F G H J K L : " forward. "Welcome," she said. "My name is Yong Hui. I'll help you lose weight and be fit in two weeks if you eat here
every day." Then she gave a menu to Wang Peng. There were few choices of food and drink on it: just rice, raw vegetables
served in vinegar, fruit and water. Wang Peng was amazed at this and especially at the prices. It cost more than a good
meal in his restaurant! He could not believe his eyes. He threw down the menu and hurried outside. On his way home he
thought about his own menu. Did it make people fat? Perhaps he should go to the library and find out. He could not have Z X C V B N M < > ?Yong Hui getting away with telling people lies! He had better do some research! At the library Wang Peng was surprised
to find that his restaurant served far too much fat and Yong Hui's far too little. Even though her customers might get
thin after eating Yong Hui's food, they were not eating enough energy-giving food to keep them fit. They would become
tired very quickly. Wang Peng felt more hopeful as he drove back home. Perhaps with a discount and a new sign he could
win his customers back. So he wrote: Want to feel fit and energetic? Come and eat here! Discounts today! Our food gives
you energy all day! The competition between the two restaurants was on!

encodeString.txt

encodeString.txt 中是在 inputString.txt 中随机截取了几段的文本,并在末尾一次性将键盘所有可见字符输入(大概818字符)

    It was obvious that the manager of the coffee shop was waiting for Li Fang to leave-he wiped the tables,
then sat down and turned on the TV-just what Li Fang needed! A sad Chinese story about lost love.What would he do? He had thrown away her Valentine gifts!She would never forgive him. This would not be a happy
Valentine's Day! his friend Li Chang hurrying by. "Hello, Lao Li," he called. "Your usual?" But Li Chang seemed not to hear.
What was the matter? Something terrible must have happened if Li Chang was not coming to eat in his restaurant as
he always did. Wang Peng followed` 1 2 3 4 5 6 7 8 9 0 - =
q w e r t y u i o p [ ] \
a s d f g h j k l ; '
z x c v b n m , . / ~ ! @ # $ % ^ & * ( ) _ +
Q W E R T Y U I O P { } |
A S D F G H J K L : "
Z X C V B N M < > ?

encoding.txt

encoding.txt 是得到的 ’ 0 ’ ’ 1 ’ 编码文件(因为无换行,所以全在同一行了,大概4032字符),待解码有818字符,大概是 8 * 818 = 6544 位,编码后只有4032 位了

111111111111110101001100011110101010011101111101111011011110101101000111000101101111110000000100110001111000000000111110101110010101100111000100111001111011111000011110000000001111101100011111000011000000100111111011000001110110001111010101001110111111010101001010010000100010111000111111000001111100111100011111101001111101001011001010111000111110000111111101110011001110101100101101111000000001111101010010001100000110100111100000000011111000100110110111011100111011101101011101101010000000001010111111011100110001111010001111010100101111100101011010011110000001011001010100110100111011101011111000000000111100011110000111110001101111001101010001100010110111000111101010000010011000111000111111010011111010010110010101110001111010100100110100001101000110110101110001110101111101110011010011111010010000000100010100111011001111110111000011111001011001111100110110110111000101000111101110111110111000111101110111110101100100011001101001101011111111111100011100000010011000111101010011100010101111010011100000011111010001111101010000111011011000011110000100110100111100000001100101111010100101111100110101010010110011110000001110011110001111100100110111001010110000100010100111111000101001100001000110110110110100110111110000001111101010011100010101111010011101010011101011001110011111100000111110011100010100110101100111100000100101011000110111000111100000010011011111101010011100010101111010011101010111100011110110110011111001111000010010110000110000110011110110100001111100100110111001010110000100010100111010001111011111110101010110010110010110110101110110100110100000010011011111110000110010100001010110100111000111111010011111010010000001001010111000111100000001011001110010110010100010111000111110110110110010001101111101010110110110000110111101110111101101011100011111110010111111000111111010010110101101010111110000001111101100100110111101110011010000011011111010101111010000010111000101100111100010110110001010011011111010100001101010111110110110111000101000111000111111010011111010010000001001010111000111111011001001101011001101001110101011110001111000011111100000011001110010001101110110100001110000001001100011110101010011101111110000000001111101011100110001000001110011101010000111011011111011110101100110000000010001011100011111000001110011100101001011011101110011111010110001011011100011100001001110101100111100001001011000011000001010100110100111010011000011100011111101001111101001000000100101011100011111010101001110111110101011110001111011000111101011010001011100011111000011111100110011000111010001011110000010011011111110010011101110001001000101100110010101100011110011101111101101000000011111001101111010101001011001110111111010001001010000011011100011100100101011100011110001110110010101110001111110000011110111101110111101010001101000110100110100110100110110110110111011011110110111110101010001111011011100010111101101110001001110110111000111111011011100011011101101110000011110110111000000111011011100001111101101110110101110110111100111011011100110011101101011010100010111110101011100111111001111100011101100111100010111010011101111110110001110110111001011111011011011010111101101110010100110101001111110111111010011111000011111000111100001111101010001111111010011111101111110110111000010111110100011111011010011011110111111110101000100111101100111110101111110110111110101111101011111101101011100011011101101110110111110110100110100110110110010111011011010111011011100111011101101110111011110110111011100111011011101111111101101101101001110110111011110111011011101100111101101111010111000111110111110110110110111111011011101100011101101011010101001111100011100111110100001111111010101001011100011110111110100000111101101110101111110101001111110100010011100011101111101101101100011110110110110011111011011011000011101101000011101011101101111111111010101011111101001011110001111101011101101100111110100001011101101110010011110001111111111101010100001111101010111110110100110111010011101101110010001111101001001110001111100111011011011111111010000001111101000101111011011100110111101101110011111111101010000

decode.c

解码只需要构造跟编码相同的哈夫曼树就可以了,不需要构造编码表

/*** Huffman 解码的实现*/#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define FILEINPUTSTRING "inputString.txt"
#define FILEENCODING "encoding.txt"
#define FILEDECODING "decoding.txt"/*** Huffman 树的结点* @param mCharacter 要编码的单个字符*/
typedef struct nodeTree {char mCharacter;struct nodeTree* mLeft;struct nodeTree* mRight;
}NodeTree, *LPNodeTree;/*** 树* 指向树的根结点的指针*/
typedef struct {LPNodeTree root;
}Tree, *LPTree;/*** 队列结点* 根据分析可知构成 Huffman 树要通过一个单调优先队列来完成* 因为要进行多次插入操作,因此选择链队列,并且由于不像常规的队列一样* 满足头部弹出,尾部进入,因此可不设头尾指针 (其实更像链表) * @param mPriority 权重,即字符出现的次数* @param mTreeNode 树的结点*/
typedef struct nodeQueue {unsigned int mPriority;NodeTree mTreeNode;struct nodeQueue* mNext;
}NodeQueue, *LPNodeQueue;/************************************************************ Huffman 树的构建                                         ** 先将每种字符保存在队列的树结点中,并将权重保存在队列中          ** 再将所有结点按照权重升序插入单调优先队列中                    ***********************************************************//*** 初始化空队列* 将队列创建出来 (空队列),各个成员都赋予初值* @return 队列头结点*/
LPNodeQueue initialQueue() {LPNodeQueue headQueueNode = (LPNodeQueue)malloc(sizeof(NodeQueue));     // 堆区申请队列头结点空间headQueueNode->mNext = NULL;headQueueNode->mPriority = 0;headQueueNode->mTreeNode.mCharacter = 0;headQueueNode->mTreeNode.mLeft = headQueueNode->mTreeNode.mRight = NULL;        // 初始化队列头结点的各个成员return headQueueNode;
}/*** 创建队列的单个结点,并将其成员赋值* @param priority 字符的权重* @param character 被统计的单个字符* @param left 树结点的左孩子* @param right 树结点的右孩子* @return 单个队列结点*/
LPNodeQueue createQueueNode(unsigned int priority, char character, LPNodeTree left, LPNodeTree right) {LPNodeQueue newQueueNode = (LPNodeQueue)malloc(sizeof(NodeQueue));newQueueNode->mNext = NULL;newQueueNode->mPriority = priority;newQueueNode->mTreeNode.mCharacter = character;newQueueNode->mTreeNode.mLeft = left;newQueueNode->mTreeNode.mRight = right;return newQueueNode;
}/*** 创建树结点* @param character 被统计的单个字符* @param left 树结点的左孩子* @param right 树结点的右孩子* @return 树结点*/
LPNodeTree createTreeNode(char character, LPNodeTree left, LPNodeTree right) {LPNodeTree newTreeNode = (LPNodeTree)malloc(sizeof(NodeTree));newTreeNode->mCharacter = character;newTreeNode->mLeft = left;newTreeNode->mRight = right;return newTreeNode;
}/*** 入队列操作,将结点按权重升序插入队列* @param headQueueNode 要插入的队列头结点* @param queueNode 要插入的队列结点*/
void enQueue(LPNodeQueue headQueueNode, LPNodeQueue queueNode) {LPNodeQueue preQueueNode = headQueueNode;   // preQueueNode 一直指向 moveQueueNode 的直接前驱结点LPNodeQueue moveQueueNode = headQueueNode->mNext;   // moveQueueNode 定位为首元结点/*** 队列不为空并且待插入结点的权值大于当前 moveQueueNode 的权值,* 则要将待插入结点往后移动* 最终定位到 preQueueNode 是 moveQUeueNode 的直接前驱结点,此时 moveQUeueNode 所处的位置应该是* 待插入结点的目标位置*/while(moveQueueNode!=NULL && queueNode->mPriority>moveQueueNode->mPriority) {preQueueNode = moveQueueNode;moveQueueNode = moveQueueNode->mNext;}queueNode->mNext = moveQueueNode;preQueueNode->mNext = queueNode;    // 找到定位后将新结点直接插入即可
}/*** 出队列操作,将头结点指向的结点移出队列并返回队列结点元素的树结点* 因为最终是需要使用树结点来构成最优二叉树,而非是队列结点* @param headQueueNode 队列头结点* @return 移出队列结点元素的树结点*/
LPNodeTree deQueue(LPNodeQueue headQueueNode) {// 空队列直接退出LPNodeQueue moveQueueNode = headQueueNode->mNext;if(moveQueueNode == NULL) {printf("QUEUE EMPTY!\n");exit(1);        // 直接中止程序}// 重新构建一个树结点,将移出的队列结点释放LPNodeTree returnTreeNode = createTreeNode(moveQueueNode->mTreeNode.mCharacter, moveQueueNode->mTreeNode.mLeft, moveQueueNode->mTreeNode.mRight);headQueueNode->mNext = moveQueueNode->mNext;    // 移除出队列首元结点moveQueueNode->mNext = NULL;free(moveQueueNode);moveQueueNode = NULL;return returnTreeNode;
}/*** 统计字符串各个字符的权重并构建单调优先队列* @param inputString 待统计的字符串,通过文件得到* @return 单调优先队列的头结点*/
LPNodeQueue getPriorityAndCreateQueue(char* inputString) {/*** 按照 ASCII 码来统计字符,使用哈希表* ASCII 码表上总共有 256 个字符*/unsigned int* priority = (unsigned int*)calloc(256, sizeof(unsigned int));for(int i = 0; inputString[i] != '\0'; ++i) {priority[inputString[i]]++;}// 创建队列LPNodeQueue headQueueNode = initialQueue();for(int i = 0; i < 256; ++i) {if(priority[i] > 0) {   // 字符数量大于 0 的才入队列LPNodeQueue newQueueNode = createQueueNode(priority[i], (char)i, NULL, NULL); // 创建队列结点,此时树结点的左右子树都是空enQueue(headQueueNode, newQueueNode);       // 将队列结点插入队列}}free(priority);return headQueueNode;
}/*** 创建 Huffman树* @param inputString 构建树的字符串,由文件得到* @return Huffman 指向 Huffman 树的根节点的指针*/
LPTree createHuffmanTree(char* inputString) {if(inputString == NULL) {printf("INPUTSTRING EMPTY!\n");exit(1);}LPNodeQueue headQueueNode = getPriorityAndCreateQueue(inputString); // 得到单调优先队列if(headQueueNode->mNext == NULL) {  // 队列为空printf("QUEUE EMPTY!\n");exit(1);}/*** 取出队列两个结点合并成为一个根结点后在插入队列,* 直到队列中只剩一个结点*/while(headQueueNode->mNext->mNext != NULL) {unsigned int priority = headQueueNode->mNext->mPriority +headQueueNode->mNext->mNext->mPriority; // 先得到将要弹出的的两个结点的权重之和LPNodeTree left = deQueue(headQueueNode);LPNodeTree right = deQueue(headQueueNode);LPNodeQueue newQueueNode = createQueueNode(priority, '0', left, right);   // 创建新的队列结点,此时有左右孩子了,而字符可以随意给一个enQueue(headQueueNode, newQueueNode);}/*** 创建树指针,指向 Huffman 树的根结点*/LPTree huffmanTree = (LPTree)malloc(sizeof(Tree));LPNodeTree newTreeNode = createTreeNode(headQueueNode->mNext->mTreeNode.mCharacter, headQueueNode->mNext->mTreeNode.mLeft, headQueueNode->mNext->mTreeNode.mRight);// 销毁最后一个队列结点以及头结点LPNodeQueue firstQueueNode =  headQueueNode->mNext;headQueueNode->mNext = NULL;free(firstQueueNode); firstQueueNode = NULL;free(headQueueNode); headQueueNode = NULL;huffmanTree->root = newTreeNode;return huffmanTree;
}/*************************************  Huffman 树创建完成,跟编码的树一模一样   ********************************************//*** 树的前序遍历*/
void preprint(LPNodeTree root) {if(root != NULL) {printf("%c ", root->mCharacter);preprint(root->mLeft);preprint(root->mRight);}
}/*** 树的中序遍历*/
void midprint(LPNodeTree root) {if(root != NULL) {midprint(root->mLeft);printf("%c ", root->mCharacter);midprint(root->mRight);}
}void testHuffmanTree() {/*** 输入的字符串定为 "aaaaabbbbcccddeffffff",即 5 个 a,4 个 b,3 个 c, 2 个 d,1 个 e 以及 6 个 f* 这样简单的字符经过人工计算得到的 Huffman 树的* 前序遍历应该为 "0 0 b a 0 0 0 e d c f"* 中序遍历应该为 "b 0 a 0 e 0 d 0 c 0 f"* 出现 0 是因为在 createHuffmanTree() 函数中创建新的队列结点时给的任意字符为 '0'* 经验证确实如此*/char* inputString = "aaaaabbbbcccddeffffff";LPTree huffmanTree = createHuffmanTree(inputString);preprint(huffmanTree->root);printf("\n");midprint(huffmanTree->root);
}/*********************************************** 根据生成的 Huffman 编码遍历 HUffman 树来解码    ** 编码为 0 则向左支移动,编码为 1 则向右支移动,直到 ** 到达叶子节点,此时该结点字符即为解码出来的字符     ************************************************//*** 解码过程* @param tree Huffman 树指针* @param encoding Huffman 编码* @return 解码后的字符串*/
char* decode(LPTree tree, char* encoding) {char* decoding = (char*)calloc(1, sizeof(char));char* tmp = NULL;LPNodeTree root = tree->root;int j = 0;for(int i = 0; encoding[i] != '\0'; ++i) {if(encoding[i] == '0') root = root->mLeft;else if(encoding[i] == '1') root = root->mRight;if(root->mLeft==NULL && root->mRight==NULL) {int size = strlen(decoding);tmp = (char*)realloc(decoding, sizeof(char) * (size+10));   // 分配足够的空间if(tmp == NULL) {printf("DECODING REALLOCATE MEMORY FAILD!\n");exit(1);}decoding = tmp;decoding[j++] = root->mCharacter;       // 将当前字符加入到解码字符串中decoding[j] = '\0';root = tree->root;              // 当前编码解码完成后后续的编码要从根结点重新开始遍历}}return decoding;
}/****************************************************    解码完成后测试一番   ***********************************//*** 在 encode.c 中测试编码的时候用的字符串是 "dacbfeabe",* 测试出来得到的编码是 "1001 01 101 00 11 1000 01 00 1000",* 因此这次直接用这一串编码看能不能得出原字符串 "dacbfeabe"* 经验证确实如此*/
void testHuffmanDecode() {char* inputString = "aaaaabbbbcccddeffffff";LPTree huffmanTree = createHuffmanTree(inputString);char* encoding = "1001011010011100001001000";char* decoding = decode(huffmanTree, encoding);printf("%s\n", decoding);
}/**********************************************  至此 decode.c 解码功能已经全部完成    ***************************************************//**************************************************** 文件操作,程序中的 inputString 应该要从文件中读取     ** 并且生成的编码也要保存到文件中                       ***************************************************//*** 从文件中读出文本,这个文件 (INPUTSTRING)是公共的、构成 Huffman 树的* 字符文件,并不是要编码或者是解码的文件* @return 保存有文本的地址*/
char* getInputString() {FILE* fp = fopen(FILEINPUTSTRING, "r");if(fp == NULL) {printf("%s OPEN FAILD!\n", FILEINPUTSTRING);exit(1);}fseek(fp, 0L, SEEK_END);    // 将光标定位到文件末尾,方便统计文件内字符数量long int size = ftell(fp);if(size == 0) {printf("%s EMPTY!\n", FILEINPUTSTRING);exit(1);}fseek(fp, 0L, SEEK_SET);    // 统计完后将光标重新定位到文件开头char* inputString = (char*)calloc(size+10, sizeof(char));   char ch;for(int i = 0; (ch = fgetc(fp)) != EOF; ++i) {      // 将数据存入 inputStringinputString[i] = ch;inputString[i+1] = '\0';}fclose(fp);return inputString;
}/*** 从文件中读取文本,这个文件 (DECODEING)中是待解码的字符* @return 保存有文本的地址*/
char* getEncoding() {FILE* fp = fopen(FILEENCODING, "r");if(fp == NULL) {printf("%s OPEN FAILD!\n", FILEENCODING);exit(1);}fseek(fp, 0L, SEEK_END);    // 将光标定位到文件末尾,方便统计文件内字符数量long int size = ftell(fp);if(size == 0) {printf("%s EMPTY!\n", FILEENCODING);exit(1);}fseek(fp, 0L, SEEK_SET);    // 统计完后将光标重新定位到文件开头char* encoding = (char*)calloc(size+10, sizeof(char));   char ch;for(int i = 0; (ch = fgetc(fp)) != EOF; ++i) {      // 将数据存入 encodingencoding[i] = ch;encoding[i+1] = '\0';}fclose(fp);return encoding;
}/*** 将生成的解码字符写入文件中* @param encoding 已解码字符串*/
void putStringInFIle(char* decoding) {FILE* fp = fopen(FILEDECODING, "w+");for(int i = 0; decoding[i] != '\0'; ++i) {fputc(decoding[i], fp);}fclose(fp);
}/**********************************************   操作流程  ***************************************/
void huffmanDecode() {// 读取 (INPUTSTRING) 文本char* inputString = getInputString();// 构建 Huffman 树LPTree huffmanTree = createHuffmanTree(inputString);// 读取 (ENCODING) 文本char* encoding = getEncoding();// 将二进制编码进行解码char* decoding = decode(huffmanTree, encoding);// 将解码字符保存至文件 (DECODING)putStringInFIle(decoding);printf("\n\nDECODE SUCCESS!\n\n");
}/***************************************************  主函数   **************************************/int main() {// testHuffmanTree();// testHuffmanDecode();huffmanDecode();return 0;
}

decode.c 的各个测试结果以及各文件内容及最后的输出文件

  • 哈夫曼树的测试 - - testHuffmanTree() 函数

    与预期结果一致
  • 哈夫曼解码的测试 - - testHuffmanDecode() 函数

    与预期结果一致
  • 运行结果 - - huffmanDecode() 函数

    与预期结果一致

inputString.txt

此文件与encode.c中使用的为同一文件读取数据,无任何改变

Festivals and celebrations Festivals and celebrations of all kinds have been held everywhere since ancient times.Most ancient
festivals would celebrate the end of cold weather,planting in spring and harvest in autumn.Sometimes
celebratewould be held after hunters had caught animals.At that time people would starve if food was
difficult to find,especially during the cold winter months.Today's festivals have many origins ,some
religious,some seasonal, and some for special people or events. Festivals of the Dead Some festivals are held to honour the dead or to satisfy the ancestors,who might return either to
help or to do harm.For the Japanese festival.Obon,people should go to clean graves and light incense
in memory of their ancestors.They also light lamps and play music because they think that this will
lead the ancestors back to earth.In Mexico,people celebrate the Day of the Dead in early November.On
this impoutant feast day,people eat food in the shape of skulls and cakes with "bones" on them.They offer
food,flowers and gifts to the dead.The Western holiday Halloween also had its origin in old beliefs about
the return of the spirits of dead people. It is now a children's festival,when they can dress up and to to
their neighbours'homes to ask for sweets.If the neighbours do not give any sweets,the children might play a
trick on them. ` 1 2 3 4 5 6 7 8 9 0 - = Festivals to Honour People Festivals can also be held to honour famous people .The Dragon Boat Festival in China honours the
famous ancient poet,Qu Yuan.In the USA Columbus Day is in memory of the arrival of Christopher Columbus in New
World.India has a national festival on October 2 to honour Mohandas Gandhi,the leader who helped gain India's
independence from Britain. Harvest Festivals Harvest and Thanksgiving festivals can be very happy events.People are grateful because their food is
gathered for the winter and the agricultural work is over.In European countries,people will usually decorate
churches and town halls with flowers and fruit,and will get together to have meals.Some people might win
awards for their farm produce,like the biggest watermelon or the most handsome rooster.China and Japan have
mid-autumn festivals,when people admire the moon and in China,enjoy mooncakes. Spring Festivals The most energetic and important festivals are the ones that look forward to the end of winter and to
the coming of spring.At the Spring Festival in China,people eat dumplings,fish and meat and may give
children lucky money in red paper.There are dragon dances and carnivals,and families celebrate the Lunar
New Year together.Some Western countries have very exciting carnivals,which take place forty days before
Easter,usually in February.These carnivals might include parades,dancing in the streets day and night,loud
music and colourful clothing of all kinds.Easter is an important religious and social festival for
Christians aroud the world.It celebrates the return of Jesus from the dead and the coming of spring and new
life.Japan’s Cherry Blossom Festival happens a little later.The country, covered with cherry tree flowers,
looks as thought it is covered with pink snow. People love to get together to eat , drink and have fun with
each other.Festivals let us enjoy life,be proud of our customs and forget our work for a little while q w e r t y u i o p [ ] \A SAD LOVE STORYLi Fang was heart-broken.It was Valentine's Day and Hu Jin had said she would meet him at the coffee
shop after work. But she didn't turn up. She could be with her friends right now laughing at him.She said
she would be there at seven o'clock, and he thought she would keep her word. He had looked forward to
meeting her all day, and now he was alone with his roses and chocolates, like a fool. Well, he was not
going to hold his breath for her to apologize. He would drown his sadness in coffee. It was obvious that the manager of the coffee shop was waiting for Li Fang to leave-he wiped the tables,
then sat down and turned on the TV-just what Li Fang needed! A sad Chinese story about lost love. a s d f g h j k l ; ' The granddaughter of the Goddess of Heaven visted the earth. Her name was Zhinü,the weaving girl. While
she was on earth she met the herd boy Niulang and they fell in love.("Just like me and Hu Jin,"thought Li Fang.)
They got married secretly, and they were very happy.("We could be like that,"thought Li Fang.)When the Goddess
of Heaven knew that her granddaughter was married to a human, she became very angry and made the weaving girl
return to Heaven.Niulang tried to follow her, but the river of stars,the Milly Way, stopped him.Finding that
Zhinu was heart-broken, her grandmother finally decided to let the couple cross the Milky Way to meet once a
year. Magpies make a bridge of their wings so the couple can cross the river to meet on the seventh day of
the seventh lunar month. People in China hope that the weather will be fine on that day, because if it is
raining, it means that Zhinü is weeping and the couple won't be able to meet. The announcer said,"This is the story of Qiqiao Festival.When foreigners hear about the story, they call
it a Chinese Valentine's story.It's a fine day today, so I hope you can all meet the one you love." z x c v b n m , . / As Li Fang set off for home, he thought,"I guess Hu Jin doesn't love me .I'll just throw these flowers
and chocolates away. I don't want them to remind me of her." So he did. ~ ! @ # $ % ^ & * ( ) _ + As he sadly passed the tea shop on the corner on his way home, he heard a voice calling him. There was Hu Jin
waving at him and calling , "why are you so late?I've been waiting for you for a long time!And I have a gift for you!" What would he do? He had thrown away her Valentine gifts!She would never forgive him. This would not be a happy
Valentine's Day! UNIT2
COME AND EAT HERE (1) Wang Peng sat in his empty restaurant feeling very frustrated. It had been a very strange morning. Usually he
got up early and prepared his menu of barbecued mutton kebabs, roast pork, stir-flied vegetables and fried rice. Q W E R T Y U I O P { } | Then by lunchtime they would all be sold. By now his restaurant ought to be full of people. But not today! Why was that?
What could have happened? He thought of his mutton, beef and bacon cooked in the hottest, finest oil. His cola was sugary
and cold, and his ice cream was made of milk, cream and delicious fruit. "Nothing could be better," he thought. Suddenly
he saw his friend Li Chang hurrying by. "Hello, Lao Li," he called. "Your usual?" But Li Chang seemed not to hear.
What was the matter? Something terrible must have happened if Li Chang was not coming to eat in his restaurant as
he always did. Wang Peng followed Li Chang into a new small restaurant. He saw a sign in the window. Tired of all
that fat? Want to lose weight? Come inside Yong Hui's slimming restaurant. Only slimming foods served here. Make
yourself thin again! Curiosity drove Wang Peng inside. It was full of people. The hostess, a very thin lady, came A S D F G H J K L : " forward. "Welcome," she said. "My name is Yong Hui. I'll help you lose weight and be fit in two weeks if you eat here
every day." Then she gave a menu to Wang Peng. There were few choices of food and drink on it: just rice, raw vegetables
served in vinegar, fruit and water. Wang Peng was amazed at this and especially at the prices. It cost more than a good
meal in his restaurant! He could not believe his eyes. He threw down the menu and hurried outside. On his way home he
thought about his own menu. Did it make people fat? Perhaps he should go to the library and find out. He could not have Z X C V B N M < > ?Yong Hui getting away with telling people lies! He had better do some research! At the library Wang Peng was surprised
to find that his restaurant served far too much fat and Yong Hui's far too little. Even though her customers might get
thin after eating Yong Hui's food, they were not eating enough energy-giving food to keep them fit. They would become
tired very quickly. Wang Peng felt more hopeful as he drove back home. Perhaps with a discount and a new sign he could
win his customers back. So he wrote: Want to feel fit and energetic? Come and eat here! Discounts today! Our food gives
you energy all day! The competition between the two restaurants was on!

encoding.txt

此文件是编码文件,也就是encode.c最终生成的那个文件,里面存有哈夫曼编码

111111111111110101001100011110101010011101111101111011011110101101000111000101101111110000000100110001111000000000111110101110010101100111000100111001111011111000011110000000001111101100011111000011000000100111111011000001110110001111010101001110111111010101001010010000100010111000111111000001111100111100011111101001111101001011001010111000111110000111111101110011001110101100101101111000000001111101010010001100000110100111100000000011111000100110110111011100111011101101011101101010000000001010111111011100110001111010001111010100101111100101011010011110000001011001010100110100111011101011111000000000111100011110000111110001101111001101010001100010110111000111101010000010011000111000111111010011111010010110010101110001111010100100110100001101000110110101110001110101111101110011010011111010010000000100010100111011001111110111000011111001011001111100110110110111000101000111101110111110111000111101110111110101100100011001101001101011111111111100011100000010011000111101010011100010101111010011100000011111010001111101010000111011011000011110000100110100111100000001100101111010100101111100110101010010110011110000001110011110001111100100110111001010110000100010100111111000101001100001000110110110110100110111110000001111101010011100010101111010011101010011101011001110011111100000111110011100010100110101100111100000100101011000110111000111100000010011011111101010011100010101111010011101010111100011110110110011111001111000010010110000110000110011110110100001111100100110111001010110000100010100111010001111011111110101011110010110010110110101110110100110100000010011011111110000110010100001010110100111000111111010011111010010000001001010111000111100000001011001110010110010100010111000111110110110110010001101111101010100110110000110111101110111101101011100011111110010111111000111111010010110101101010101110000001111101100100110111101110011010000011011111010101011010000010111000101100111100010110110001010011011111010100001101010101110110110111000101000111000111111010011111010010000001001010111000111111011001001101011001101001110101011110001111000011111100000011001110010001101110110100001110000001001100011110101010011101111110000000001111101011100110001000001110011101010000111011011111011110101100110000000010001011100011111000001110011100101001011011101110011111010110001011011100011100001001110101100111100001001011000011000001010100110100111010011000011100011111101001111101001000000100101011100011111010101001110111110101011110001111011000111101011010001011100011111000011111100110011000111010001011110000010011011111110010011101110001001000101100110010101100011110011101111101101000000011111001101111010101001011001110111111010001001010000011011100011100100101011100011110001110110010101110001111110000011110111101110111101010001101000110100110100110100110110110110111011011110110111110101011001111011011100010111101101110001001110110111000111111011011100011011101101110000011110110111000000111011011100001111101101110110101110110111100111011011100110011101101011010100010111110101011100111111001111100011101100111100010111010011101111110110001110110111001011111011011011010111101101110010100110101001111110111111010011111000011111000111100001111101010001111111010011111101111110110111000010111110100011111011010011011110111111110101000100111101100111110101111110110111110101111101011111101101011100011011101101110110111110110100110100110110110010111011011010111011011100111011101101110111011110110111011100111011011101111111101101101101001110110111011110111011011101100111101101111010111000111110111110110110110111111011011101100011101101011010101101111100011100111110100001111111010101101011100011110111110100000111101101110101111110101001111110100010011100011101111101101101100011110110110110011111011011011000011101101000011101011101101111111111010101111111101001011110001111101011101101100111110100001011101101110010011110001111111111101010110001111101010101110110100110111010011101101110010001111101001001110001111100111011011011111111010000001111101000101111011011100110111101101110011111111101010000

decoding.txt

此文件是解码encoding.txt文件之后生成的文本文件

    It was obvious that the manager of the coffee shop was waiting for Li Fang to leave-he wiped the tables,
then sat down and turned on the TV-just what Li Fang needed! A sad Chinese story about lost love.What would he do? He had thrown away her Valentine gifts!She would never forgive him. This would not be a happy
Valentine's Day! his friend Li Chang hurrying by. "Hello, Lao Li," he called. "Your usual?" But Li Chang seemed not to hear.
What was the matter? Something terrible must have happened if Li Chang was not coming to eat in his restaurant as
he always did. Wang Peng followed` 1 2 3 4 5 6 7 8 9 0 - =
q w e r t y u i o p [ ] \
a s d f g h j k l ; '
z x c v b n m , . / ~ ! @ # $ % ^ & * ( ) _ +
Q W E R T Y U I O P { } |
A S D F G H J K L : "
Z X C V B N M < > ?

总结

对比 encodeString.txt 和 decoding.txt 可以发现,两文本完全相同,说明编码解码功能实现正常,整个流程如下:

读取 inputString.txt 中的内容后生成基本的哈夫曼树,编码过程还需生成每个字符的编码,然后读取 encodString.txt 中的内容,此文件内容就是待编码文本,需要压缩后发送给别处,编码成功后将生成的编码保存到 encoding.txt 文件中发送给接收方,接收方得到此文件后可以进行解码,读取同一个 inputString.txt 文件生成与发送方一模一样的哈夫曼树,然后对 encoding.txt 文件中的编码进行解码操作,将解码后的字符串保存到 decoding.txt 文件中

Huffman 编码的实现(C语言)相关推荐

  1. huffman编码译码器用c语言,基于哈弗曼编码的数据压缩C语言实现

    haod 摘要 数据压缩技术是一项重要实用的信息技术.信息时代的到来,信息量迅速增长,使得数据压缩也显得越来越重要.数据压缩有多种编码方法,大致可分为无损压缩编码和有损压缩编码.其中,Huffman ...

  2. HuffMan编码C语言实现

    HuffMan编码C语言实现 实现了一种编码方式,和两种解码方式. 解码一种使用的是叶子回溯根. 一种使用了从根遍历过程. 代码: HuffManEncoding // // Created by Z ...

  3. huffman编码压缩c语言,用Huffman编码对文件进行压缩的C语言实现

    本文介绍了采用Huffman编码对ASCII码文件进行压缩的基本原理,并用C语言程序实现了这个压缩过程.文中给出了比较完整的C语言程序代码,可以直接用于调试实验. 福 建电 脑 21 0 2年第 1期 ...

  4. 基于Huffman编码的C语言解压缩文件程序

    #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h>//极大 ...

  5. 数据压缩实验三:用c语言实现Huffman编码和压缩效率分析

    实验原理: 1.Huffman编码 Huffman编码是一种无失真的编码方式,是可变字长编码(VLC)的一种. Huffman编码基于信源的概率统计模型,它的基本思路是: 出现概率大的信源符号编长码, ...

  6. Huffman编码的C语言实现

    实验原理 Huffman 编码 (1) Huffman Coding (霍夫曼编码)是一种无失真编码的编码方式,Huffman 编码是可变字长编码(VLC)的一种. (2)Huffman 编码基于信源 ...

  7. Huffman 编码的编程与实现 C语言

    一 .目的: 1.    掌握Huffman树的概念.存储结构: 2.    掌握建立Huffman树和Huffman编码的方法: 二 .环境: operating system version:Wi ...

  8. huffman图像编码C语言,Huffman编码 数据结构 C语言

    为解决广大童鞋的数据结构实验问题写下本文:(只做参考哦.) 实验要求: Huffman编码(二叉树) l实验目的:熟练掌握二叉树应用(Huffman编码)的基本算法实现. l实现功能:对输入的一串电文 ...

  9. 采用Huffman编码进行数据压缩

    文章目录 问题 实验环境 程序组成 实现思路 如何用二进制0/1表示字符 '0' / '1' 源代码下载 程序运行和结果: 总结 问题 利用哈夫曼编码将英文文献进行压缩 注:哈夫曼算法及原理见博客ht ...

最新文章

  1. R语言广义线性模型函数GLM、广义线性模型(Generalized linear models)、GLM函数的语法形式、glm模型常用函数、常用连接函数、逻辑回归、泊松回归、系数解读、过散度分析
  2. CSS3 background-image背景图片相关介绍
  3. ecshop后台实现用ajax动态修改/更新用户评论的时间
  4. day17.Python中lambda表达式应用
  5. 请求solr服务器未响应,solr与tomcat整合
  6. async/await
  7. 我的docker随笔11:Dockerfile编写
  8. torch--[Pytorch函数] .masked_fill_() ;关于pytorch中@和*的用处
  9. docker容器中的网络原理(单机模式下的容器网络)
  10. Linux端BaiduPCS-Go使用方法
  11. CF1051D Bicolorings
  12. 408考研题错误之处
  13. 基于Python的IMDB电影评论文本分类
  14. 2020年9月程序员工资最新统计,结果万万没想到
  15. 任务管理器已被管理员停用 解决方法
  16. SpringBoot集成MongoDB实现两种CRUD
  17. Android音视频开发之ExoPlayer(一):快速入门ExoPlayer
  18. geany配置python_在python虚拟环境中使用geany
  19. Python语言程序设计——实验八
  20. Blender 3.5 面的操作(二)

热门文章

  1. SmartScore 64 Professional Edition v11.3.76 WiN 专业乐谱扫描识别软件
  2. android9.0自动使用24小时制
  3. [论文笔记] Detection of Glottal Closure Instants from Speech Signals: CNN Method
  4. 学习Python的入门建议及资料分享
  5. 计算机未连接到网络,电脑一直提示未连接到internet怎么办?
  6. 秒解UTF-8带来的烦恼
  7. 产品模块化设计的前世今生
  8. Wordpress限制游客访问权限(免插件) 实现禁止游客访问功能
  9. 本地计算机 feifei pc,局域网中其它计算机对共享打印机的访问方法
  10. Java数据安全须知