具体原理及定义请百度,下面直接进行实现。具体实现过程是: 统计若干字符出现的频率,将其按频率(权重)升序存放进队列中,每次从队列中取两个结点合成一颗二叉树,这两个结点的根节点是取出来两个结点的字符的权重和,并且将新的结点放入队列中,满足队列依旧是升序排列,一直持续直到队列中仅剩最后一个结点,此时这个结点就是 Human 树的根节点,构成的树也叫最优二叉树
下面将分为两个文件,作用分别是 Huffman 编码以及解码,不再模拟传输过程,仅仅是简单模拟数据压缩以及恢复过程。
由于分为了两个文件,而两个文件都需要得到每个字符的Huffman编码(或者说Huffman树),因此两个文件构造Huffman树的过程是一样的,并且都读取同一个文件的数据来生成Huffman树
/**
* Huffman 编码的实现
*/
#include
#include
#include
#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'; // 左分支填 0
travelHuffmanTree(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) { // 将数据存入 inputString
inputString[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) { // 将数据存入 encodeString
encodeString[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 的各个测试结果以及各文件内容及最后的输出文件
文件 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 STORY
Li 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 中是在 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 是得到的 ’ 0 ’ ’ 1 ’ 编码文件(因为无换行,所以全在同一行了,大概4032字符),待解码有818字符,大概是 8 * 818 = 6544 位,编码后只有4032 位了
111111111111110101001100011110101010011101111101111011011110101101000111000101101111110000000100110001111000000000111110101110010101100111000100111001111011111000011110000000001111101100011111000011000000100111111011000001110110001111010101001110111111010101001010010000100010111000111111000001111100111100011111101001111101001011001010111000111110000111111101110011001110101100101101111000000001111101010010001100000110100111100000000011111000100110110111011100111011101101011101101010000000001010111111011100110001111010001111010100101111100101011010011110000001011001010100110100111011101011111000000000111100011110000111110001101111001101010001100010110111000111101010000010011000111000111111010011111010010110010101110001111010100100110100001101000110110101110001110101111101110011010011111010010000000100010100111011001111110111000011111001011001111100110110110111000101000111101110111110111000111101110111110101100100011001101001101011111111111100011100000010011000111101010011100010101111010011100000011111010001111101010000111011011000011110000100110100111100000001100101111010100101111100110101010010110011110000001110011110001111100100110111001010110000100010100111111000101001100001000110110110110100110111110000001111101010011100010101111010011101010011101011001110011111100000111110011100010100110101100111100000100101011000110111000111100000010011011111101010011100010101111010011101010111100011110110110011111001111000010010110000110000110011110110100001111100100110111001010110000100010100111010001111011111110101010110010110010110110101110110100110100000010011011111110000110010100001010110100111000111111010011111010010000001001010111000111100000001011001110010110010100010111000111110110110110010001101111101010110110110000110111101110111101101011100011111110010111111000111111010010110101101010111110000001111101100100110111101110011010000011011111010101111010000010111000101100111100010110110001010011011111010100001101010111110110110111000101000111000111111010011111010010000001001010111000111111011001001101011001101001110101011110001111000011111100000011001110010001101110110100001110000001001100011110101010011101111110000000001111101011100110001000001110011101010000111011011111011110101100110000000010001011100011111000001110011100101001011011101110011111010110001011011100011100001001110101100111100001001011000011000001010100110100111010011000011100011111101001111101001000000100101011100011111010101001110111110101011110001111011000111101011010001011100011111000011111100110011000111010001011110000010011011111110010011101110001001000101100110010101100011110011101111101101000000011111001101111010101001011001110111111010001001010000011011100011100100101011100011110001110110010101110001111110000011110111101110111101010001101000110100110100110100110110110110111011011110110111110101010001111011011100010111101101110001001110110111000111111011011100011011101101110000011110110111000000111011011100001111101101110110101110110111100111011011100110011101101011010100010111110101011100111111001111100011101100111100010111010011101111110110001110110111001011111011011011010111101101110010100110101001111110111111010011111000011111000111100001111101010001111111010011111101111110110111000010111110100011111011010011011110111111110101000100111101100111110101111110110111110101111101011111101101011100011011101101110110111110110100110100110110110010111011011010111011011100111011101101110111011110110111011100111011011101111111101101101101001110110111011110111011011101100111101101111010111000111110111110110110110111111011011101100011101101011010101001111100011100111110100001111111010101001011100011110111110100000111101101110101111110101001111110100010011100011101111101101101100011110110110110011111011011011000011101101000011101011101101111111111010101011111101001011110001111101011101101100111110100001011101101110010011110001111111111101010100001111101010111110110100110111010011101101110010001111101001001110001111100111011011011111111010000001111101000101111011011100110111101101110011111111101010000
解码只需要构造跟编码相同的哈夫曼树就可以了,不需要构造编码表
/**
* Huffman 解码的实现
*/
#include
#include
#include
#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) { // 将数据存入 inputString
inputString[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) { // 将数据存入 encoding
encoding[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 的各个测试结果以及各文件内容及最后的输出文件
此文件与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 STORY
Li 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!
此文件是编码文件,也就是encode.c最终生成的那个文件,里面存有哈夫曼编码
111111111111110101001100011110101010011101111101111011011110101101000111000101101111110000000100110001111000000000111110101110010101100111000100111001111011111000011110000000001111101100011111000011000000100111111011000001110110001111010101001110111111010101001010010000100010111000111111000001111100111100011111101001111101001011001010111000111110000111111101110011001110101100101101111000000001111101010010001100000110100111100000000011111000100110110111011100111011101101011101101010000000001010111111011100110001111010001111010100101111100101011010011110000001011001010100110100111011101011111000000000111100011110000111110001101111001101010001100010110111000111101010000010011000111000111111010011111010010110010101110001111010100100110100001101000110110101110001110101111101110011010011111010010000000100010100111011001111110111000011111001011001111100110110110111000101000111101110111110111000111101110111110101100100011001101001101011111111111100011100000010011000111101010011100010101111010011100000011111010001111101010000111011011000011110000100110100111100000001100101111010100101111100110101010010110011110000001110011110001111100100110111001010110000100010100111111000101001100001000110110110110100110111110000001111101010011100010101111010011101010011101011001110011111100000111110011100010100110101100111100000100101011000110111000111100000010011011111101010011100010101111010011101010111100011110110110011111001111000010010110000110000110011110110100001111100100110111001010110000100010100111010001111011111110101011110010110010110110101110110100110100000010011011111110000110010100001010110100111000111111010011111010010000001001010111000111100000001011001110010110010100010111000111110110110110010001101111101010100110110000110111101110111101101011100011111110010111111000111111010010110101101010101110000001111101100100110111101110011010000011011111010101011010000010111000101100111100010110110001010011011111010100001101010101110110110111000101000111000111111010011111010010000001001010111000111111011001001101011001101001110101011110001111000011111100000011001110010001101110110100001110000001001100011110101010011101111110000000001111101011100110001000001110011101010000111011011111011110101100110000000010001011100011111000001110011100101001011011101110011111010110001011011100011100001001110101100111100001001011000011000001010100110100111010011000011100011111101001111101001000000100101011100011111010101001110111110101011110001111011000111101011010001011100011111000011111100110011000111010001011110000010011011111110010011101110001001000101100110010101100011110011101111101101000000011111001101111010101001011001110111111010001001010000011011100011100100101011100011110001110110010101110001111110000011110111101110111101010001101000110100110100110100110110110110111011011110110111110101011001111011011100010111101101110001001110110111000111111011011100011011101101110000011110110111000000111011011100001111101101110110101110110111100111011011100110011101101011010100010111110101011100111111001111100011101100111100010111010011101111110110001110110111001011111011011011010111101101110010100110101001111110111111010011111000011111000111100001111101010001111111010011111101111110110111000010111110100011111011010011011110111111110101000100111101100111110101111110110111110101111101011111101101011100011011101101110110111110110100110100110110110010111011011010111011011100111011101101110111011110110111011100111011011101111111101101101101001110110111011110111011011101100111101101111010111000111110111110110110110111111011011101100011101101011010101101111100011100111110100001111111010101101011100011110111110100000111101101110101111110101001111110100010011100011101111101101101100011110110110110011111011011011000011101101000011101011101101111111111010101111111101001011110001111101011101101100111110100001011101101110010011110001111111111101010110001111101010101110110100110111010011101101110010001111101001001110001111100111011011011111111010000001111101000101111011011100110111101101110011111111101010000
此文件是解码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 文件中