Huffman编码与解码
2017-03-09 14:19
387 查看
哈夫曼树又称为最优二叉树 哈夫曼编码是指一种可变长前缀码 即字符编码位数不统一 也无重复前缀 甚至有些情况下 哈夫曼编码被称为最优编码 于是着手简单的看了理论之后立即去实现 因为还要上课 总的时间大约花了我一天多时间结束 调完bug的一瞬间也是感觉世界真美好的 0-0
---C语言编程
---辅助栈手动实现
---重要函数及体现过程:
------------------------------ 统计字符概率(StatCodedChar )
------------------------------ 按照概率排序(BubbleSort(冒泡))
------------------------------ 创建哈夫曼树(CreateHuffmanTree)
------------------------------ 遍历树并将编码元素放入编码表(LoopFOrderTree(非递归前序))
------------------------------ 编码(CreateHuffmancode)
------------------------------ 解码(HuffmanDecoder)
------------------------------ 释放哈夫曼树(FreeHuffmanTree)
------------------------------ 释放编码表(FreeCoderTable)
---编码输出到文件
---编码表输出到文件
---可改进:在解码时从文件中读取编码表到程序 从而达到编码与解码的完全分离使用(To Do)
编码表输出文件结果:
编码输出文件结果:
---C语言编程
---辅助栈手动实现
---重要函数及体现过程:
------------------------------ 统计字符概率(StatCodedChar )
------------------------------ 按照概率排序(BubbleSort(冒泡))
------------------------------ 创建哈夫曼树(CreateHuffmanTree)
------------------------------ 遍历树并将编码元素放入编码表(LoopFOrderTree(非递归前序))
------------------------------ 编码(CreateHuffmancode)
------------------------------ 解码(HuffmanDecoder)
------------------------------ 释放哈夫曼树(FreeHuffmanTree)
------------------------------ 释放编码表(FreeCoderTable)
---编码输出到文件
---编码表输出到文件
---可改进:在解码时从文件中读取编码表到程序 从而达到编码与解码的完全分离使用(To Do)
编码表输出文件结果:
编码输出文件结果:
#include <stdio.h> #include <stdlib.h> #include <windows.h> #define TRUE 1 #define FALSE 0 #define BOOL int #define LEFT_CODE '0' #define RIGHT_CODE '1' typedef struct huffmannode { BOOL IsSrcChar; char CodingNum; int Weight; char CodedChar; struct huffmannode *pLeftChlid; struct huffmannode *pRightChlid; struct huffmannode *pFather; struct huffmannode *pNext; }HuffmanNode; typedef struct codertablenode { char CodedChar; char* CoderNum; int CoderPlacesNum; }CoderTableNode; typedef struct codelist { char CodedNum; struct codelist *pNext; }CodeList; typedef struct stack { HuffmanNode *tree; struct stack *pNext; }Stack; typedef struct MyStack { Stack *stack; int count; }Stack_Top; CoderTableNode *pCoderTable = NULL;//编码表 int CoderTableLen = -1; //当前字符是否在之前出现过 return 出现过返回1 没有出现过:0 int IsAppearBefore(char src_string[],char src_char,int char_appear_index) { while(char_appear_index > 0) { if(src_char == src_string[--char_appear_index]) return 1; } return 0; } //统计字符概率 HuffmanNode* StatCodedChar(char src_string[],int len_src) { int count; HuffmanNode *pHead = NULL; HuffmanNode *pTemp = NULL; //进行统计 for(count = 0;count<len_src;count++) { if( !IsAppearBefore(src_string,src_string[count],count) ) { pTemp = (HuffmanNode *)malloc(sizeof(HuffmanNode)); pTemp->IsSrcChar = TRUE; pTemp->CodingNum = LEFT_CODE; pTemp->Weight = 1; pTemp->CodedChar = src_string[count]; pTemp->pRightChlid = NULL; pTemp->pLeftChlid = NULL; pTemp->pFather = NULL; //用pNext指针来贯穿链表 头添加 if(pHead != NULL) { pTemp->pNext = pHead; pHead->pFather = pTemp; } else { pTemp->pNext = NULL; pTemp->pFather = NULL; } pHead = pTemp; } else { pTemp = pHead; while(pTemp) { if(pTemp->CodedChar == src_string[count]) { pTemp->Weight++; break; } pTemp = pTemp->pNext; } } } return pHead; } //冒泡排序:小->大 void BubbleSort(HuffmanNode **pHead) { char temp_char; int temp_weigtht; HuffmanNode *pTemp = NULL; HuffmanNode *pLoopPoint = NULL; HuffmanNode *pLoopPoint_in = NULL; if(pHead == NULL)return ; pTemp = pLoopPoint = *pHead; while(pLoopPoint->pNext) { pLoopPoint_in = pLoopPoint; while(pLoopPoint_in->pNext) { if(pLoopPoint_in->Weight > pLoopPoint_in->pNext->Weight) { temp_char = pLoopPoint_in->CodedChar; temp_weigtht = pLoopPoint_in->Weight; pLoopPoint_in->Weight = pLoopPoint_in->pNext->Weight; pLoopPoint_in->CodedChar = pLoopPoint_in->pNext->CodedChar; pLoopPoint_in->pNext->Weight = temp_weigtht; pLoopPoint_in->pNext->CodedChar = temp_char; } pLoopPoint_in = pLoopPoint_in->pNext; } pLoopPoint = pLoopPoint->pNext; } } //对已排序的数据建造哈夫曼树 HuffmanNode* CreateHuffmanTree(HuffmanNode **pHead) { int count; HuffmanNode *pTemp = NULL; HuffmanNode *HeadLastPoint = NULL; if(pHead == NULL)return NULL; while(*pHead != NULL) { pTemp =(HuffmanNode *)malloc(sizeof(HuffmanNode)); pTemp->pLeftChlid = *pHead; pTemp->pLeftChlid->CodingNum = LEFT_CODE;//左孩子编码值为0 pTemp->pLeftChlid->pFather = pTemp;//更新父亲 pTemp->pRightChlid = (*pHead)->pNext; pTemp->pRightChlid->CodingNum = RIGHT_CODE;//右孩子编码值为1 pTemp->pRightChlid->pFather = pTemp;//更新父亲 pTemp->IsSrcChar = FALSE; pTemp->CodingNum = LEFT_CODE; pTemp->Weight = (*pHead)->Weight + (*pHead)->pNext->Weight; pTemp->CodedChar = -1; pTemp->pFather = NULL; pTemp->pNext = NULL; for(count = 0;count<2;count++)//断开原有结构 头指针后移 { HeadLastPoint = (*pHead); (*pHead) = (*pHead)->pNext; if(HeadLastPoint->IsSrcChar == TRUE) { HeadLastPoint->pNext = NULL; } } if(*pHead == NULL) break; HeadLastPoint = *pHead; while(pTemp->Weight > HeadLastPoint->Weight && HeadLastPoint->pNext != NULL) { HeadLastPoint = HeadLastPoint->pNext; } if(HeadLastPoint == *pHead && HeadLastPoint->Weight >= pTemp->Weight) { pTemp->pNext = *pHead; (*pHead)->pFather = pTemp; *pHead = pTemp; } else { if(HeadLastPoint->pNext == NULL && HeadLastPoint->Weight < pTemp->Weight) { HeadLastPoint->pNext = pTemp; pTemp->pFather = HeadLastPoint; pTemp->pNext = NULL; } else { HeadLastPoint->pFather->pNext = pTemp; pTemp->pNext = HeadLastPoint; pTemp->pFather = HeadLastPoint->pFather; HeadLastPoint->pFather = pTemp; } } } return pTemp; } int GetCharCount(HuffmanNode *pHead) { int CharCount = 0; HuffmanNode *ptemp = NULL; if(pHead == NULL)return -1; ptemp = pHead; while(ptemp) { CharCount++; ptemp = ptemp->pNext; } return CharCount; } //-------------------------------辅助栈------------------------------------- void InitStack(Stack_Top** stacktop) { *stacktop = (Stack_Top *)malloc(sizeof(Stack_Top)); (*stacktop)->stack = NULL; (*stacktop)->count = 0; } void StackPush(Stack_Top *stacktop,HuffmanNode* val) { Stack *pTemp = NULL; pTemp = (Stack *)malloc(sizeof(Stack)); pTemp->tree = val; pTemp->pNext = NULL; if(stacktop->stack != NULL) { pTemp->pNext = stacktop->stack; } stacktop->stack = pTemp; stacktop->count++; return ; } HuffmanNode* StackPop(Stack_Top *stacktop) { HuffmanNode *val = NULL; if(stacktop->stack == NULL) return NULL; else { Stack *pTemp = stacktop->stack; val = (stacktop->stack)->tree; stacktop->stack = stacktop->stack->pNext; free(pTemp); stacktop->count--; return val; } } //-----------------------------辅助栈--------------------------------------- //编码并加入表中 void CallBackCode(HuffmanNode *Node,CoderTableNode *CoderTable) { int count_Places; int count; int count_Add; HuffmanNode *pTemp = NULL; CodeList *pHead = NULL; CodeList *pDel = NULL; CodeList *pTemp_CodeList = NULL; if(Node == NULL || CoderTable == NULL)return ; count_Places = 0; pTemp = Node; while(pTemp->pFather) { pTemp_CodeList = (CodeList*)malloc(sizeof(CodeList)); pTemp_CodeList->CodedNum = pTemp->CodingNum; //头添加 if(pHead == NULL) { pTemp_CodeList->pNext = NULL; } else { pTemp_CodeList->pNext = pHead; } pHead = pTemp_CodeList; count_Places++; pTemp = pTemp->pFather; } //放入编码表 for(count = 0;count<CoderTableLen;count++) { if(pCoderTable[count].CodedChar == -1) break; } pCoderTable[count].CodedChar = Node->CodedChar; pCoderTable[count].CoderPlacesNum = count_Places; pCoderTable[count].CoderNum = (char *)malloc(sizeof(char)*count_Places); for(count_Add = 0;count_Add<count_Places;count_Add++) { pCoderTable[count].CoderNum[count_Add] = pHead->CodedNum; pDel = pHead; pHead = pHead->pNext; free(pDel); pDel = NULL; } } //非递归前序遍历 void LoopFOrderTree(HuffmanNode *tree) { Stack_Top *stack = NULL; if(tree == NULL) return ; InitStack(&stack); while(1) { while(tree != NULL) { StackPush(stack,tree); tree = tree->pLeftChlid; } tree = StackPop(stack); if(tree == NULL) return ; if(tree->IsSrcChar == TRUE) { CallBackCode(tree,pCoderTable);//编码并加入表中 } tree = tree->pRightChlid; } } //编码 void CreateHuffmancode(char src_string[],int len_src) { int count; int count_in; int count_print; CoderTableNode *pTemp = NULL; FILE *pFile = NULL; if(src_string == NULL || len_src <= 0) return ; pTemp = pCoderTable; if(fopen_s(&pFile,"./Huffmancode.txt","w") != 0)return ; printf(">>>编码结果输出文件在此程序源文件同目录下 名为:Huffmancode.txt\n\n");//编码结果输出文件 for(count = 0;count<len_src;count++) { for(count_in = 0;count_in<CoderTableLen;count_in++) { if(pTemp[count_in].CodedChar == src_string[count]) { for(count_print = 0;count_print<pTemp[count_in].CoderPlacesNum;count_print++) { //printf("%c",pTemp[count_in].CoderNum[count_print]); fputc(pTemp[count_in].CoderNum[count_print],pFile); } break; } } } printf(">>>编码完成\n\n"); fclose(pFile); } //输出编码表到文件 void PrintToFileOfCoderTable() { int count; int count_in; FILE *pFile = NULL; if(pCoderTable == NULL || CoderTableLen <= 0)return ; if(fopen_s(&pFile,"./CoderTable.txt","w") != 0)return ; printf(">>>编码表结果输出文件在此程序源文件同目录下 名为:CoderTable.txt\n\n");//编码表结果输出文件 for(count = 0;count<CoderTableLen;count++) { fputc(pCoderTable[count].CodedChar,pFile); fputc(':',pFile); for(count_in = 0;count_in<pCoderTable[count].CoderPlacesNum;count_in++) { fputc(pCoderTable[count].CoderNum[count_in],pFile); } fseek(pFile,4,SEEK_CUR); } } //递归释放哈夫曼树 void FreeHuffmanTree(HuffmanNode *pHunffmanTree) { if(pHunffmanTree == NULL)return ; FreeHuffmanTree(pHunffmanTree->pLeftChlid); FreeHuffmanTree(pHunffmanTree->pRightChlid); free(pHunffmanTree); pHunffmanTree = NULL; } //释放编码表 void FreeCoderTable() { int count; if(pCoderTable == NULL)return ; for(count = 0;count<CoderTableLen;count++) { free(pCoderTable[count].CoderNum); pCoderTable[count].CoderNum = NULL; } free(pCoderTable); pCoderTable = NULL; } //前期准备过程 编码 void HuffmanEncoder(char src_string[],int len_src) { int CharCount; HuffmanNode *pHead = NULL; HuffmanNode *pHunffmanTree = NULL; if(src_string == NULL || len_src <= 0) return ; //准备过程 pHead = StatCodedChar(src_string,len_src);//统计字符概率 BubbleSort(&pHead);//按照概率排序 CharCount = GetCharCount(pHead);//统计编码元素个数 pHunffmanTree = CreateHuffmanTree(&pHead);//创建哈夫曼树 pCoderTable = (CoderTableNode *)malloc(sizeof(CoderTableNode)*CharCount);//申请编码表 CoderTableLen = CharCount; memset(pCoderTable,-1,sizeof(CoderTableNode)*CharCount); LoopFOrderTree(pHunffmanTree);//遍历树并放入编码表 PrintToFileOfCoderTable();//编码表结果输出文件 CreateHuffmancode(src_string,len_src);//编码过程 FreeHuffmanTree(pHunffmanTree);//回收空间 } //按照编码表匹配并打印 返回编码占位数 int SearchIsRightAndPrint(char huffmancodechar[],int LoopCount) { int count; int count_in; int LoopCountTemp; if(huffmancodechar == NULL || LoopCount < 0)return -1; //查找匹配 for(count = 0;count<CoderTableLen;count++) { LoopCountTemp = LoopCount; for(count_in = 0;count_in<pCoderTable[count].CoderPlacesNum;count_in++) { if(pCoderTable[count].CoderNum[count_in] == huffmancodechar[LoopCountTemp]) { LoopCountTemp++; } else { break; } } //匹配成功 打印 if(count_in == pCoderTable[count].CoderPlacesNum) { printf("%c",pCoderTable[count].CodedChar); return p a2ee CoderTable[count].CoderPlacesNum; } } return -1; } //解码 void HuffmanDecoder(char *filename) { int filesize; int SearchResult; int LoopCount; FILE *pFile = NULL; char *huffmancodechar = NULL; if(fopen_s(&pFile,filename,"r") != 0)return ; //得到编码 fseek(pFile,0,SEEK_END);//偏移至文件尾 filesize = ftell(pFile);//得到文件大小 rewind(pFile);//重新指向文件开头 huffmancodechar = (char *)malloc(sizeof(char)*filesize); memset(huffmancodechar,0,sizeof(char)*filesize); if( fgets(huffmancodechar,filesize+1,pFile) == NULL) { return ; //printf("%s",huffmancodechar); } fclose(pFile); //解码 LoopCount = 0; while(LoopCount <= filesize) { SearchResult = SearchIsRightAndPrint(huffmancodechar,LoopCount);//按照编码表匹配并打印 if(SearchResult == -1) break ; else LoopCount+=SearchResult; } printf("\n"); FreeCoderTable();//释放编码表 } int main() { char arr[] = "fdg;d;gfherwrewrwqersddfshghdsfgghjdsfgfhasfashhsdtgsdghhhfghdhdfyuuyuoipasopuyiuhhfyuareryewgrelgeryuthreunrblerbytbyltjbysbhbewtbhetbhbtwebrltberwhtberlktbertbhewrlbtlhewrbtlethgsdfhgkdsfhglghsdfhgjldsfhgjhdsfglhdsflghdfhgjldsfhgjfdhgldshgdsflghdsfhgdsghjdhgdfhglkdffsgdsgsdgfgsgfhfdhdf"; HuffmanEncoder(arr,strlen(arr)); HuffmanDecoder("./Huffmancode.txt"); system("pause"); return 0; }
相关文章推荐
- huffman编码与解码
- Huffman编码与解码的实现
- Huffman编码与解码_C语言实现
- PHP实现Huffman编码/解码的示例代码
- C#实现Huffman编码和解码
- Haskell实现Huffman编码解码
- Huffman编码解码
- 数据压缩三-Huffman编码与解码
- huffman编码与解码
- C#实现Huffman编码和解码
- Java实现-Huffman编码与解码
- huffman编码解码与huffman树
- Huffman编码与解码C++程序
- huffman编码与解码
- 用VB.Net接收邮件并解码-WBWY
- 解码混淆过的堆栈跟踪信息(Decoding Obfuscated Stack Traces)
- 加壳技术-DRx解码阻止调试
- JS URL 编码 PHP 解码{%u5F00%u53D1}
- Base64 编码和解码源程序(C 语言)
- Android 用MediaCodec实现视频硬解码