Huffman编码实现文件的压缩与解压缩。
以前没事的时候写的,c++写的,原理很简单,代码如下:
1 #include <cstdio> 2 #include <cstdlib> 3 #include <iostream> 4 #include <string> 5 //#include <bitset> 6 #include <fstream> 7 #include <ctime> 8 9 const int maxCodeNum = 256; 10 11 using namespace std; 12 13 //哈夫曼树的树节点 14 struct HaffTreeNode{ 15 HaffTreeNode * lNode; 16 HaffTreeNode * rNode; 17 string haffCode; 18 int value; 19 int alpha; 20 HaffTreeNode() 21 :lNode(NULL), rNode(NULL), haffCode(""), value(0), alpha(0){;} 22 }; 23 24 //链表节点,用于生成哈夫曼树 25 struct ListNode{ 26 struct HaffTreeNode HaffTreeNode; 27 ListNode *nextListNode; 28 ListNode() 29 :nextListNode(NULL){;} 30 }; 31 32 //用与保存输入文件统计信息的hash表 33 typedef struct HashTable{ 34 int value; 35 int alpha; 36 HashTable() 37 :value(0), alpha(0){} 38 //比较函数用于排序使用 39 inline friend int operator-(const HashTable & a, const HashTable & b){ 40 return a.value - b.value; 41 } 42 } HashTable; 43 HashTable charHashTable[maxCodeNum]; 44 45 46 //排序使用的比较大小的函数 47 int hashComp(const void * a, const void * b) 48 { 49 return *((HashTable *)a) - *((HashTable *)b); 50 } 51 52 53 //创建一个哈夫曼树 54 HaffTreeNode * createHaffTreeNodeTree(HashTable table[]) 55 { 56 ListNode *root = new ListNode; 57 ListNode *next = root; 58 for(int i = 0; /*i < maxCodeNum - 1*/; ++i){ 59 if(table[i].value == 0)//如果对应的码不为0,就为其分配一个树节点 60 continue; 61 next->HaffTreeNode.alpha = table[i].alpha; 62 next->HaffTreeNode.value = table[i].value; 63 if(i ==maxCodeNum - 1) 64 break; 65 next->nextListNode = new ListNode; 66 next = next->nextListNode; 67 } 68 69 while(root->nextListNode != NULL){ 70 ListNode * currNode = new ListNode; 71 currNode->HaffTreeNode.value = root->HaffTreeNode.value + root->nextListNode->HaffTreeNode.value; 72 currNode->HaffTreeNode.lNode = &(root->HaffTreeNode); 73 currNode->HaffTreeNode.rNode = &(root->nextListNode->HaffTreeNode); 74 root = root->nextListNode->nextListNode; //概率最小的两个码相加组成一个新的节点 75 76 ListNode * nextNode = root; 77 ListNode * prevNode = NULL; 78 while(nextNode != NULL && currNode->HaffTreeNode.value > nextNode->HaffTreeNode.value){ 79 prevNode = nextNode; 80 nextNode = nextNode->nextListNode; 81 } 82 83 if(prevNode == NULL){//将这个新的节点插入到所有节点之前(currNode目前还是最小的) 84 currNode->nextListNode = nextNode; 85 root = currNode; 86 }else{//插入到节点中间或者节点之后的位置 87 prevNode->nextListNode = currNode; 88 currNode->nextListNode = nextNode; 89 } 90 }//在这个list中所有的元素遍历完成之后返回 91 return &(root->HaffTreeNode);//返回书的根节点的哈弗满节点,这个节点已经构造成为了一棵树 92 } 93 94 string huffmanCodeTable[maxCodeNum]; 95 string haffCode; 96 97 //给哈夫曼树编码 98 void createHaffmanTable(HaffTreeNode * root) 99 { 100 if(root->lNode == NULL && root->rNode == NULL){ 101 huffmanCodeTable[root->alpha] = haffCode; 102 haffCode.erase(haffCode.length() - 1); 103 return; 104 }//给各个节点赋予相应的哈夫曼编码 105 haffCode.append("0"); 106 createHaffmanTable(root->lNode); 107 108 haffCode.append("1"); 109 createHaffmanTable(root->rNode); 110 111 if(!haffCode.empty()){ 112 haffCode.erase(haffCode.length() - 1); 113 } 114 return; 115 } 116 117 //将生成的二进制长串编码转换成字符用于存储在压缩文件中 118 unsigned char StrToBin(string str) 119 { 120 unsigned int ans =0; 121 int tmpNum = atoi(str.c_str()); 122 int multiNum = 1; 123 while(tmpNum != 0){ 124 ans += tmpNum%10*multiNum; 125 tmpNum/=10; 126 multiNum *= 2; 127 } 128 return (unsigned char) ans; 129 } 130 131 //用于将压缩文件的字符转换成huffman编码 132 string BinToStr(unsigned char c) 133 { 134 string tmpNumStr; 135 while(c != 0){ 136 tmpNumStr.insert(tmpNumStr.begin(), (unsigned char)(c%2 + '0')); 137 c /= 2; 138 } 139 if(tmpNumStr.length() < 8){ 140 tmpNumStr.insert(tmpNumStr.begin(), 8 - tmpNumStr.length(), '0'); 141 } 142 return tmpNumStr; 143 } 144 145 //下面是将huffman码译成原字符的程序 146 char huffDecode(HaffTreeNode * root, string & code) 147 { 148 unsigned int i; 149 for( i = 0; i < code.length(); ++i){ 150 if(root->alpha == 0) 151 root = (code[i] - '0')?root->rNode:root->lNode; 152 else{ 153 code.erase(0, i); 154 return root->alpha; 155 } 156 } 157 if(root->alpha !=0){ 158 code.erase(0, i); 159 return root->alpha; 160 } 161 code.clear(); 162 return '\0'; 163 } 164 165 166 167 int main(int argc, char ** argv) 168 { 169 if(argc != 3){ 170 printf("Error number of arguments!\n"); 171 } 172 FILE * fin = fopen(argv[1], "r"); 173 int c = 0; 174 while((c = fgetc(fin)) != EOF && c != '\n'){ 175 putchar(c); 176 putchar('*'); 177 charHashTable[c].alpha = c; 178 charHashTable[c].value++; 179 } 180 181 qsort(charHashTable, sizeof(charHashTable)/sizeof(charHashTable[0]), 182 sizeof(charHashTable[0]), hashComp); 183 /*建立有关本文件的huffman树*/ 184 HaffTreeNode * haffTreeRoot = createHaffTreeNodeTree(charHashTable); 185 createHaffmanTable(haffTreeRoot); 186 187 cout << "Char\tTimes\tCodes"; 188 for(int i = 0; i < maxCodeNum; ++i){ 189 if(charHashTable[i].value != 0){ 190 cout << (char)charHashTable[i].alpha << "\t" << charHashTable[i].value 191 << "\t" << huffmanCodeTable[charHashTable[i].alpha] << "\n"; 192 } 193 } 194 195 FILE * fout; 196 if((fout = fopen(argv[2], "w")) == NULL){ 197 perror("open output file error!\n"); 198 } 199 rewind(fin); 200 string buf; 201 202 while((c = fgetc(fin)) != EOF){ /*将文件通过huffman码转来进行压缩*/ 203 //printf("The char is %c ", c); 204 buf += huffmanCodeTable[c]; 205 cout << buf << endl; 206 if(buf.length() > 8){ //当转换的字符得到的huffman码达到8的时候转换成一个字符填入目标文件 207 fputc(StrToBin(buf.substr(0, 8)), fout); 208 buf.erase(0, 8); 209 } 210 } 211 212 int leftZero = 0; //保存不到8位的余留位的个数 213 if(!buf.empty()){ 214 buf.append((leftZero = 8 - buf.length()), '0'); 215 fputc(StrToBin(buf), fout); 216 } 217 218 if(fclose(fin) == -1) 219 perror("close file error!\n"); 220 if(fclose(fout) == -1) 221 perror("close file error!\n"); 222 223 if((fin = fopen(argv[2], "rb")) == NULL)//打开压缩文件,开始解码 224 perror("Open file error!\n"); 225 if((fout = fopen("huffmanDecompose.txt", "w")) == NULL) 226 perror("Open file error!\n"); 227 228 //开始解码 229 int bin; 230 buf.clear(); 231 while((bin = fgetc(fin)) != EOF){ 232 buf.append(BinToStr(bin)); 233 } 234 235 while(buf.length() - leftZero != 0 && !buf.empty()){ 236 fputc(huffDecode(haffTreeRoot, buf), fout); 237 } 238 if(fclose(fin) != 0) 239 perror("close file error!\n"); 240 if(fclose(fout) != 0) 241 perror("close file error!\n"); 242 return 0; 243 }
./a.out file1 file2
file1:输入文件
file2:输出文件(压缩后)
要锁完成后会将文压缩文件解压到huffmanDecompose.txt这个文件中