Greedy:Huffman编码

上次我在http://www.cnblogs.com/Philip-Tell-Truth/p/4787067.html这里,稍微讲了一下一种很普通的贪婪的算法,其实这个算法一开始是用来做压缩程序的,就是最著名的Huffman压缩算法

           

  那么这个算法是怎么样的呢,我们知道,我们的字符如果以ASCII的形式表示的话(只算英文和数字),其实就是一堆二进制代码,一个char型字符占一个字节。那么我们想到怎么压缩呢?

  因为我们的文档不可能打印那一些不可能出现在屏幕的字符,那么我们完全可以把这些字符去掉,然后制一套我们自己的字符表(二进制对应),不一定是1个字节对应一个字符,我们可以6个位对应一个字符这个样子,这样会对文档有一定的压缩。

  然后我们再想,在一篇文档中,每一个字符出现的概率不是相等的,有一些字母会出现很多次,比如a,b,s,这些,而有一些会出现的相对较少比如z,q这些,那么我们可不可以根据这个来压缩文件呢?答案是肯定的,既然我们已经确定了我们要根据概率来压缩文件,我们很自然地就会想到贪婪算法。

  我们先来看Fence Repair这一道题,这一道题最后我们是把最小的板占据树的最低空间,同样的,对于出现概率不一的字母,我们也可以给他构建一个这样的生成树(不同深度,分叉不同,对应的二进位的位数和状态(0,1)也会不同)。

       比如有一个这样的文档,里面的字符出现的概率对应如下:

a 000 10 30
e 001 15 45
i 010 12 36
s 011 3 9
t 100 4 12
space 101 13 19
newline 110 1 3
总和     174

  我们在不考虑其出现的概率进行压缩的情况下,我们重新制了一个对应表,那么最后出来的比特率就会降低很多

现在我们尝试用概率结合贪婪算法继续进行压缩,我们知道,如果我们要构建一棵生成树的话,我们可以这样办,出现概率较高的字母,我们给他二进制的位比较少,出现概率比较低的字母,我们给他二进制位比较高,然后这样定义以后我们就会有一个很直观的结论,就是因为出现概率比较高的字母占的比特率会比较低,那么我们的整体占的比特数就会相应的低。这是一种贪婪的思想。

然后我们来想,怎么构建这样的字母表呢?我们知道,由于我们最后写到文件上肯定不能直接写ASCII码,不然我们做这些就没意义了,我们最后是要写比特到上面去的,也就是一堆01010101,那么我们既然只有0,1两种状态,我们就可以想到我们可以用二叉树的形式去构建,我们把字母放在节点上,然后结合成一棵二叉树,我们可以这样规定,如果字母在节点的左边,那么这个字母的下一个二进位就是0,在右边就是1。

那么我们最后就会得到一个二叉树,由于我们是要把出现概率较低的字母放在深度比较低的地方,我们可以先把概率较低的字母先结合起来,然后结合成一个新的节点,然后和其他节点继续结合,有点像修篱笆那题。大概就像下图那样

然后我们就得到了一棵生成树,现在我们就可以给所有的字母重新编码了,那么怎么编码呢?刚才我们说了,出现在比较高的字母他的编码会比较长,在深度比较低的字母编码会比较短(节点往左走相应的二进位就代表0,往右走就代表1)我们很容易就可以得到下面的编码表

a 001 10 30
e 01 15 30
i 10 12 24
s 00000 3 15
t 0001 4 16
space 11 13 26
newline 00001 1 5
总和     146

可以看到,最后编码占的总空间更小了,达到了我们压缩的目的。

最后的问题就很简单了,怎么实现这个生成最优编码树呢?我们维护一个堆就可以了,建立完树以后就可以根据字母在树的位置给文件写编码拉!

下面是代码,全实现,有点长

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #define MAX 255//可读字符类型最多为255(相当于散列了)
  5 #define UNSIGNED_LONG_32_MAX 4294967296ULL
  6 #define SUFFIX ".hfc"
  7
  8 typedef int Position;
  9 typedef struct node
 10 {
 11     char symbol;
 12     int sum;
 13     struct node *left, *right;
 14 }NODE, *Heap;
 15 typedef struct node_list
 16 {
 17     int weight;
 18     int code_gragh[MAX];
 19 }LIST;
 20 typedef struct _tree
 21 {
 22     int sum;
 23     char symbol;
 24 }Hf_Store;
 25
 26 //局部函数定义
 27 Heap *Read_TextFile(int *,FILE **,Hf_Store **,char []);
 28 Heap *Read_PackagedFile(int *, FILE **, Hf_Store **,int *,int *);
 29 void Inivilzie_store(int[]);
 30 void BulidHeap(Heap *, int);
 31 void Percolate_Up(Heap *, int, Position);
 32 NODE *DeleteMin(Heap *, int *);
 33 NODE *Bulid_Tree(Heap *,const int);
 34 void Push_in(NODE *, Heap *, int *);
 35 void Unpackged_File_to_File(NODE *, FILE *,const int,const int,char[]);
 36 void Write_In_Code_List(NODE *, int *, int[],const int,LIST[]);
 37 void Write_in_file(NODE *,FILE *,Hf_Store *,const int,char []);
 38 void *Allocate_In_Memory(const int, int *, int *, FILE *, LIST[]);
 39 void Destory_Node(NODE *);
 40 void Binary_to_ANSCII(NODE *,FILE *, FILE *,const int,const int);
 41 void Op_OverFlow(unsigned long[], const int);
 42 void Op_LackFlow(unsigned long[], const int);
 43 Heap *Put_Array_To_Heap(Hf_Store *, const int);
 44 inline void Put_size_to_array(const int, const int,const int, int[]);
 45 inline void Put_arrary_to_size(int[],int *,int *,int *,int *);
 46 inline void Destroy_Heap_node_and_HfTree(Heap **, Hf_Store **,NODE *);
 47
 48 void Inivilzie_store(int store[])
 49 {
 50     for (int i = 0; i < MAX; i++) store[i] = 0;
 51 }
 52
 53 Heap *Read_TextFile(int *length, FILE **fp, Hf_Store **Hf_Tree, char file_name[261])
 54 {
 55     int i, word_sum = 0, tmp, j = 1,_store[MAX];
 56     NODE *tmp_node = NULL;
 57
 58     Inivilzie_store(_store);//初始化读取数组
 59     while (1)
 60     {
 61         fflush(stdin);
 62         printf("请输入文件名   ");
 63         scanf("%s", file_name);
 64         if ((*fp = fopen(file_name, "r")) == NULL)
 65             printf("\a文件不存在,请重新输入\n\n");
 66         else break;
 67     }
 68     for (;;)
 69     {
 70         tmp = fgetc(*fp);
 71         if (feof(*fp)) break;
 72         if (!_store[tmp]) word_sum++;
 73         _store[tmp]++;
 74     }
 75     *length = word_sum;
 76     Heap *word_arrary = (Heap *)malloc(sizeof(Heap)*(word_sum + 1));//堆从1位置开始
 77     *Hf_Tree = (Hf_Store *)malloc(sizeof(Hf_Store)*word_sum);
 78     for (i = 0; i < MAX; i++)
 79         if (_store[i]){
 80             tmp_node = (NODE *)malloc(sizeof(NODE));
 81             tmp_node->sum = _store[i];
 82             tmp_node->right = tmp_node->left = NULL;
 83             tmp_node->symbol = i;
 84             word_arrary[j] = tmp_node;
 85             j++;
 86         }
 87     BulidHeap(word_arrary, *length);
 88     for (int i = 0; i < word_sum; i++)
 89     {
 90         (*Hf_Tree)[i].symbol = (word_arrary[i + 1])->symbol;
 91         (*Hf_Tree)[i].sum = (word_arrary[i + 1])->sum;
 92     }
 93     return word_arrary;
 94 }
 95
 96 Heap *Read_PackagedFile(int *length, FILE **fp, Hf_Store **Hf_Tree,int *sum_byte,int *sum_bit_left,char source_file_name[])
 97 {
 98     char file_name[261], *suffix = SUFFIX;
 99     int inform[3];//文件头的三个信息
100     int sum_bit, scr_size;
101
102     while (1)
103     {
104         fflush(stdin);
105         printf("请输入你要解压文件的文件名(自动添加后缀.hfc)   ");
106         scanf("%s", file_name);
107         strcat(file_name, suffix);
108         if ((*fp = fopen(file_name, "rb")) == NULL)//直接用二进制模式读取
109             printf("\a文件不存在,请重新输入\n\n");
110         else break;
111     }
112
113     fread(&scr_size, sizeof(int), 1, *fp);
114     fread(source_file_name, sizeof(char), scr_size, *fp);
115     source_file_name[scr_size] = ‘\0‘;//补一个斜杠0
116     printf("\n源文件名字为%s", source_file_name);
117
118     fread(inform, sizeof(int), 3, *fp);
119     Put_arrary_to_size(inform, &sum_bit, sum_byte, sum_bit_left, length);
120     *Hf_Tree = (Hf_Store *)malloc(sizeof(Hf_Store) * (*length));
121     fread(*Hf_Tree, sizeof(Hf_Store), (*length), *fp);
122
123     Heap *word_arrary = Put_Array_To_Heap(*Hf_Tree, *length);
124
125     return word_arrary;
126 }
127
128 void BulidHeap(Heap *word_arrary, int size)//线性建堆法,不多说
129 {
130     Position i;
131     if (size % 2) for (i = size - 1; i > 1; i -= 2)  Percolate_Up(word_arrary, size, i / 2);//如果是奇数
132     else for (i = size; i > 1; i -= 2) Percolate_Up(word_arrary, size, i / 2);
133 }
134
135 void Percolate_Up(Heap *heap, int size, Position i)
136 {
137     Position s1, s2;
138     NODE *tmp = heap[i];
139     for (; i <= size;)
140     {
141         s1 = 2 * i; s2 = s1 + 1;
142         if (s2 <= size)
143         {
144             if ((*heap[s1]).sum <= (*heap[s2]).sum)
145             {
146                 if (tmp->sum > (heap[s1])->sum) { heap[i] = heap[s1]; i = s1; }
147                 else break;
148             }
149             else
150             {
151                 if (tmp->sum > (heap[s2])->sum){ heap[i] = heap[s2]; i = s2; }
152                 else break;
153             }
154         }
155         else
156         {
157             if (s1 <= size)
158             {
159                 if (tmp->sum > (heap[s1])->sum) { heap[i] = heap[s1]; i = s1; break; }
160                 else break;
161             }
162             else break;
163         }
164     }
165     heap[i] = tmp;
166 }
167
168 NODE *DeleteMin(Heap *heap, int *size)//Floyd算法
169 {
170     Position i = 1, s1, s2, s;
171     NODE *out = heap[1];
172     NODE *tmp = heap[(*size)--];
173     for (; i <= *size;)
174     {
175         s1 = 2 * i; s2 = s1 + 1;
176         if (s2 <= *size)
177         {
178             if ((heap[s1])->sum <= (heap[s2])->sum) { heap[i] = heap[s1]; i = s1; }
179             else { heap[i] = heap[s2]; i = s2; }
180         }
181         else
182         {
183             if (s1 <= *size) { heap[i] = heap[s1]; i = s1; break; }
184             else break;
185         }
186     }
187     for (; i > 1;)
188     {
189         if (i % 2 == 1)//注意是这里判断奇偶性
190         {
191             s = (i - 1) / 2;
192             if ((heap[s])->sum > tmp->sum) { heap[i]= heap[s]; i = s; }
193             else break;
194         }
195         else
196         {
197             s = i / 2;
198             if ((heap[s])->sum > tmp->sum) { heap[i] = heap[s]; i = s; }
199             else break;
200         }
201     }
202     heap[i] = tmp; return out;
203 }
204
205 void Push_in(NODE *tmp_new, Heap *heap, int *size)
206 {
207     Position i, s;
208     for (i = ++(*size); i > 1;)
209     {
210         if (i % 2 == 1)//注意是这里判断奇偶性
211         {
212             s = (i - 1) / 2;
213             if ((heap[s])->sum > tmp_new->sum) { heap[i] = heap[s]; i = s; }
214             else break;
215         }
216         else
217         {
218             s = i / 2;
219             if ((heap[s])->sum > tmp_new->sum) { heap[i] = heap[s]; i = s; }
220             else break;
221         }
222     }
223     heap[i] = tmp_new;
224 }
225
226 inline void Put_size_to_array(const int sum_bit, const int sum_byte,const int length,int inform[])
227 {
228     inform[0] = sum_byte;//文件字节数
229     inform[1] = sum_bit;//文件实际比特数
230     inform[2] = length;//文件堆的大小
231 }
232
233 inline void Destroy_Heap_node_and_HfTree(Heap **Heap, Hf_Store **Hf_Tree,NODE *Thead)
234 {
235     free(*Heap); *Heap = NULL;
236     free(*Hf_Tree); *Hf_Tree = NULL;
237     Destory_Node(Thead);
238 }
239
240 inline void Put_arrary_to_size(int inform[], int *sum_bit, int *sum_byte, int *sum_bit_left, int *length)
241 {
242     *sum_byte = inform[0];//文件字节数
243     *sum_bit = inform[1];//文件实际比特数
244     *length = inform[2];//文件堆的大小
245     *sum_bit_left = (*sum_byte * 32) - (*sum_bit);
246 }
247
248 void Destory_Node(NODE *T)
249 {
250     if (T == NULL) return;
251
252     Destory_Node(T->left);
253     Destory_Node(T->right);
254     free(T);
255 }
256
257 void Op_OverFlow(unsigned long M[],const int length)
258 {
259     int overflow = 0;
260     unsigned long long out_flow;
261
262     for (int i = 0; i < length; i++)
263     {
264         out_flow = (unsigned long long)M[i] << 1;
265
266         if (overflow) {
267             out_flow += 1UL; overflow = 0;//一定要记得归零
268         }
269         if (out_flow >= UNSIGNED_LONG_32_MAX){
270             out_flow -= UNSIGNED_LONG_32_MAX;
271             M[i] = (unsigned long)out_flow;
272             overflow = 1;
273         }
274         else M[i] = (unsigned long)out_flow;
275     }
276 }
277
278 void Op_LackFlow(unsigned long M[], const int length)//TODO:完成这个函数
279 {
280     unsigned long long lack_flow;
281
282     for (int i = length - 1; i >= 0; i--)
283     {
284         lack_flow = (unsigned long long)M[i] << 1;
285
286         if (lack_flow >= UNSIGNED_LONG_32_MAX)
287         {
288             lack_flow -= UNSIGNED_LONG_32_MAX;
289             M[i] = (unsigned long)lack_flow;
290             if (i != length - 1)
291                 M[i + 1] += 1UL;
292         }
293         else M[i] = (unsigned long)lack_flow;
294     }
295 }
296
297 Heap *Put_Array_To_Heap(Hf_Store *Hf_Tree, const int length)
298 {
299     Heap *word_arrary = (Heap *)malloc(sizeof(Heap)*(length + 1));//堆从1位置开始
300     NODE *tmp = NULL;;
301
302     for (int i = 0; i < length; i++)
303     {
304         tmp = (NODE *)malloc(sizeof(NODE));
305         tmp->left = tmp->right = NULL;
306         tmp->symbol = Hf_Tree[i].symbol;
307         tmp->sum = Hf_Tree[i].sum;
308         word_arrary[i + 1] = tmp;
309     }
310     return word_arrary;
311 }
  1 #include "plug.h"
  2
  3 int main()//Huffman压缩程序
  4 {
  5     Heap *heap = NULL; NODE *Tree_Heap = NULL; FILE *fp = NULL; Hf_Store *Hf_Tree = NULL;
  6     int length; char choice;
  7     char source_file_name[261];//文件名长度最多为260
  8
  9     while (1)
 10     {
 11         printf("Huffman无损压缩程序-----By Philip 2015.7.20----Version 1.0\n");
 12         printf("====================================================\n");
 13         printf("请输入选项\nY(压缩某文件)\tJ(解压某文件)\tQ(退出程序)   ");
 14         while (1)
 15         {
 16             fflush(stdin);
 17             scanf("%c", &choice);
 18             if (choice == ‘Y‘ || choice == ‘J‘ || choice == ‘Q‘) break;
 19             printf("\n\a错误的输入,请重新输入   ");
 20         }
 21         if (choice == ‘Y‘)
 22         {
 23             heap = Read_TextFile(&length, &fp, &Hf_Tree, source_file_name);
 24             Tree_Heap = Bulid_Tree(heap, length);
 25             Write_in_file(Tree_Heap,fp,Hf_Tree,length,source_file_name);
 26             Destroy_Heap_node_and_HfTree(&heap, &Hf_Tree, Tree_Heap);
 27             system("pause");
 28         }
 29         else if (choice == ‘J‘)
 30         {
 31             int sum_bit_left, sum_byte;
 32
 33             heap = Read_PackagedFile(&length, &fp, &Hf_Tree, &sum_byte, &sum_bit_left,source_file_name);
 34             Tree_Heap = Bulid_Tree(heap, length);
 35             Unpackged_File_to_File(Tree_Heap, fp, sum_byte, sum_bit_left,source_file_name);
 36             Destroy_Heap_node_and_HfTree(&heap, &Hf_Tree, Tree_Heap);
 37             system("pause");
 38         }
 39         else break;
 40         printf("\n\n\n"); system("cls");
 41     }
 42     printf("\n");system("pause");return 0;
 43 }
 44
 45 NODE *Bulid_Tree(Heap *heap,const int size)
 46 {
 47     int size_tmp = size, i = 0;
 48     NODE *tmp1 = NULL, *tmp2 = NULL, *tmp_new = NULL;
 49
 50     for (; size_tmp > 1;)//不断deleteMin
 51     {
 52         tmp1 = DeleteMin(heap, &size_tmp);
 53         tmp2 = DeleteMin(heap, &size_tmp);
 54
 55         tmp_new = (NODE *)malloc(sizeof(NODE));
 56         tmp_new->left = tmp1; tmp_new->right = tmp2; tmp_new->symbol = ‘\0‘;
 57         tmp_new->sum = tmp1->sum + tmp2->sum;
 58
 59         Push_in(tmp_new, heap, &size_tmp);
 60     }
 61     return heap[1];
 62 }
 63
 64 void Write_in_file(NODE *Thead, FILE *fp, Hf_Store *Hf_Tree, const int length,char source_file_name[])
 65 {
 66     int sum_bit = 0, Depth = 0, sum_byte, sum_left, inform[3], code_List[MAX], scr_size = strlen(source_file_name);
 67     char *suffix = SUFFIX, out_name[MAX + 1], choice = ‘N‘;
 68     FILE *out_fp = NULL;
 69     LIST code_Hash[MAX];
 70
 71     Write_In_Code_List(Thead, &sum_bit, code_List, Depth, code_Hash);
 72
 73     void *Memory_Pool = Allocate_In_Memory(sum_bit, &sum_byte, &sum_left, fp, code_Hash);
 74     Put_size_to_array(sum_bit, sum_byte, length, inform);
 75
 76     fclose(fp); fp = NULL;//这个时候可以关闭文件流了
 77
 78     printf("请输入你要输出的压缩文件的文件名(自动添加后缀.hfc)   ");
 79     while (choice == ‘N‘)
 80     {
 81         fflush(stdin);
 82         scanf("%s", out_name);
 83         strcat(out_name, suffix);
 84
 85         if ((out_fp = fopen(out_name, "r")) != NULL)
 86         {
 87             printf("文件已存在,是否覆盖?(Y or N)   ");
 88             while (1)
 89             {
 90                 fflush(stdin);
 91                 scanf("%c", &choice);
 92                 if (choice == ‘Y‘) break;
 93                 else if (choice == ‘N‘) { printf("请重新指定文件名   "); break; }
 94                 else printf("你的输入有误,请重新输入  ");
 95                 fclose(out_fp);//先关掉out_fp
 96             }
 97         }
 98         else break;
 99     }
100     printf("%s文件即将被写入\n", out_name);
101
102     if ((out_fp = fopen(out_name, "wb+")) == NULL){
103         printf("文件写入失败\n");
104         system("pause"); return;
105     }
106
107     fwrite(&scr_size, sizeof(int), 1, out_fp);
108     fwrite(source_file_name, sizeof(char), scr_size, out_fp);
109     fwrite(inform, sizeof(int), 3, out_fp);
110     fwrite(Hf_Tree, sizeof(Hf_Store), length, out_fp);
111     fwrite(Memory_Pool,sizeof(unsigned long), sum_byte, out_fp);
112
113     printf("对%s写入成功!\n", out_name);
114
115     fclose(out_fp); out_fp = NULL;//记得关文件
116     free(Memory_Pool);//记得释放这个
117 }
118
119 void Write_In_Code_List(NODE *T, int *sum_bit, int code_List[],const int Depth,LIST code_Hash[])
120 {
121     if (T->symbol != ‘\0‘)
122     {
123         *sum_bit += Depth*T->sum;
124         code_Hash[T->symbol].weight = Depth;
125         for (int i = 0; i < Depth; i++) (code_Hash[T->symbol]).code_gragh[i] = code_List[i];
126     }
127     else//这里如果不是\0那么一定存在左右节点
128     {
129         code_List[Depth] = 0;
130         Write_In_Code_List(T->left, sum_bit, code_List, Depth + 1,code_Hash);
131         code_List[Depth] = 1;
132         Write_In_Code_List(T->right, sum_bit, code_List, Depth + 1,code_Hash);
133     }
134 }
135
136 void *Allocate_In_Memory(const int sum_bit, int *sum_byte, int *sum_bit_left, FILE *fp, LIST code_Hash[])
137 {
138     int tmp, i;
139
140     if (!(sum_bit % 32)) *sum_byte = sum_bit / 32;
141     else *sum_byte = sum_bit / 32 + 1;//一个字节等于八位(unsigned long是32个字节-1)
142     *sum_bit_left = (*sum_byte) * 32 - sum_bit;
143
144     unsigned long *Memory_Pool = (unsigned long *)malloc(*sum_byte*sizeof(unsigned long));
145     memset(Memory_Pool, 0, *sum_byte*sizeof(unsigned long));
146     Memory_Pool[0] = 1;///记住要把第一个弄成1,不然0放不进去
147
148     fseek(fp, 0L, SEEK_SET);//将指针定位到开头
149     for (; ;)
150     {
151         tmp = fgetc(fp);
152         if (feof(fp)) break;
153
154         for (i = 0; i < code_Hash[tmp].weight; i++)
155         {
156             Op_OverFlow(Memory_Pool,*sum_byte);
157             if ((code_Hash[tmp]).code_gragh[i] == 0) Memory_Pool[0]= Memory_Pool[0] | 0X00;//0的时候就按0
158             else Memory_Pool[0] = Memory_Pool[0] | 0X01;                                   //1的时候按1
159         }
160     }
161     return (void *)Memory_Pool;
162 }
163
164 void Binary_to_ANSCII(NODE *T_head, FILE *fp_source, FILE *fp_out, const int sum_byte, const int sum_bit_left)
165 {
166     int i;
167     NODE *tmp;
168     unsigned long *M = (unsigned long *)malloc(sizeof(unsigned long)*sum_byte);//拿一块大的区域
169     fread(M, sizeof(unsigned long), sum_byte, fp_source);//把数据录入这个区域
170
171     for (i = 0; i < sum_bit_left; i++)//首先去掉最后一个区域的空位数字
172         Op_LackFlow(M, sum_byte);
173     for (i = 0; i < T_head->sum; i++)
174     {
175         for (tmp = T_head; tmp->symbol == ‘\0‘;)
176         {
177             if ((M[sum_byte - 1] & 2147483648UL) == 2147483648UL) tmp = tmp->right;//如果是1那么往左走
178             else tmp = tmp->left;                                                   //如果是0往右走
179             Op_LackFlow(M, sum_byte);
180         }
181         fputc(tmp->symbol, fp_out);
182     }
183     free(M);
184 }
185
186 void Unpackged_File_to_File(NODE *T_head, FILE *fp, const int sum_byte, int sum_bit_left,char source_file_name[])
187 {
188     FILE *out_fp = NULL;
189     char choice = ‘N‘, position[268] = "hfc.";
190
191     printf("输出文件的位置将在本程序所在目录的创建,名称为%s%s\n", position, source_file_name);
192     while (choice == ‘N‘)
193     {
194         strcat(position, source_file_name);
195         if ((out_fp = fopen(position, "r")) != NULL)
196         {
197             printf("文件已存在,是否覆盖?(Y or N)   ");
198             while (1)
199             {
200                 fflush(stdin);
201                 scanf("%c", &choice);
202                 if (choice == ‘Y‘) break;
203                 else if (choice == ‘N‘) { printf("请重新指定文件名   "); break; }
204                 else printf("你的输入有误,请重新输入  ");
205                 fclose(out_fp);//先关掉out_fp
206             }
207             if (choice == ‘N‘)
208             {
209                 scanf("%s", source_file_name);
210                 strcat(position, source_file_name);
211             }
212         }
213         else break;
214     }
215     printf("%s文件即将被写入\n", position);
216
217     if ((out_fp = fopen(position, "w")) == NULL){
218         printf("文件写入失败\n");
219         system("pause"); return;
220     }
221     Binary_to_ANSCII(T_head, fp, out_fp,sum_byte,sum_bit_left);
222
223     printf("\n成功写入%s文件!\n\n", position);
224
225     fclose(out_fp); out_fp = NULL;
226     fclose(fp); fp = NULL;//记得关源文件
227 }

最后程序我是写出来了,但是这个程序有几个问题:

1.程序不支持中文,只要代码不在ASCII的都不行,也就是音频压缩这些统统不支持,当然了改也很简单,不过要用到widechar或者unicode编码,我就权当练一下就没改下去了

2.其实不改不是我懒,是因为我觉得这个程序有一个致命的BUG,那就是当程序很大的时候压缩会相当的慢,我觉得瓶颈是在我写入比特位的时候的方法不对,但是我去CSDN问了一下,貌似也没什么人回答我,我也不知道怎么改,还望看到这个帖子的人给我一点启示。。。。感激不尽

时间: 2024-10-30 23:37:35

Greedy:Huffman编码的相关文章

Jcompress: 一款基于huffman编码和最小堆的压缩、解压缩小程序

前言 最近基于huffman编码和最小堆排序算法实现了一个压缩.解压缩的小程序.其源代码已经上传到github上面: Jcompress下载地址 .在本人的github上面有一个叫Utility的repository,该分类下面有一个名为Jcompress的目录便是本文所述的压缩.解压缩小程序的源代码.后续会在Utility下面增加其他一些实用的小程序,比如基于socket的文件断点下载小程序等等.如果你读了此文觉得还不错,不防给笔者的github点个star, 哈哈.在正式介绍Jcompres

Huffman编码学习笔记

主要是在学算导,觉得算导译到中国真是中国人民的福音. 一.编码 编码就是选择有意义的01串,令其首尾相接组成文本.我们并非可以随便挑选01串,原因在于它们是首尾相接的,这为我们识别造成了一些困难.比如说我们不能在文本000000中分清字符00与000. 一般我们使用的方式是定长字符:但更好的方式是前缀码,算导中写道"虽然我们这里不会证明,但与任何字符编码相比,前缀码确实可以保证达到最优数据压缩率.",这显然是一个flag,将来一定会有比前缀码更好的编码方式的. 二.Huffman编码便

基于Huffman编码的压缩软件的Python实现

哈夫曼编码是利用贪心算法进行文本压缩的算法,其算法思想是首先统计文件中各字符出现的次数,保存到数组中,然后将各字符按照次数升序排序,挑选次数最小的两个元素进行连结形成子树,子树的次数等于两节点的次数之和,接着把两个元素从数组删除,将子树放入数组,重新排序,重复以上步骤.为了解压,在压缩时首先往文件中填入huffman编码的映射表的长度,该表的序列化字符串,编码字符串分组后最后一组的长度(编码后字符串长度模上分组长度),最后再填充编码后的字符串.本算法中以一个字节,8位作为分组长度,将编码后二进制

基于二叉树和数组实现限制长度的最优Huffman编码

具体介绍详见上篇博客:基于二叉树和双向链表实现限制长度的最优Huffman编码 基于数组和基于链表的实现方式在效率上有明显区别: 编码256个符号,符号权重为1...256,限制长度为16,循环编码1w次,Release模式下.基于链表的耗时为8972ms,基于数组的耗时为1793ms,速度是链表实现方式的5倍. 详细代码例如以下: //Reference:A fast algorithm for optimal length-limited Huffman codes.pdf,http://p

Huffman 编码压缩算法

前两天发布那个rsync算法后,想看看数据压缩的算法,知道一个经典的压缩算法Huffman算法.相信大家应该听说过 David Huffman 和他的压缩算法—— Huffman Code,一种通过字符出现频率,Priority Queue,和二叉树来进行的一种压缩算法,这种二叉树又叫Huffman二叉树 —— 一种带权重的树.从学校毕业很长时间的我忘了这个算法,但是网上查了一下,中文社区内好像没有把这个算法说得很清楚的文章,尤其是树的构造,而正好看到一篇国外的文章<A Simple Examp

为什么Huffman编码不会发生冲突

关于Huffman编码,这里有一篇漂亮的介绍 http://coolshell.cn/articles/7459.html 似乎介绍Huffman编码的都会有一句“Huffman编码不会发生冲突,即不存在某个编码是另一个编码的前缀”.但是也似乎都没有解释为什么. 细细想明白了之后,觉得似乎又没什么深奥的原理.废话少说,上图. 以上面的图为例子,我们假设这是一个生成Huffman编码的二叉树. 1)所谓的Huffman编码其实就是各个叶节点的路径编码.比如节点H就是010(用左0,右1的规则) 2

Huffman编码

Huffman编码用来解决最小二叉树问题... 用堆来维护,所用用优先队列(稍微修改一下放入方式)每次将两个权值最小的取出来,然后把他们的和再放进去,重复这个操作就可以解决了 1 #include<iostream> 2 #include<queue> 3 using namespace std; 4 typedef long long ll; 5 6 int main(){ 7 priority_queue<int>que; 8 int n, x; 9 cin>

UVa10954 Add All (Huffman编码,优先队列)

链接:http://vjudge.net/problem/UVA-10954 分析:Huffman编码建立过程,每次贪心选取两个当前最小数,从集合中删去,然后把它们的和放回集合,用优先队列去模拟集合而且可以优化取最小数过程. 1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 using namespace std; 5 6 const int maxm = 500 + 5; 7 8 int

Huffman编码之文件的解/压缩

问题描述:           生活中文件压缩技术可谓随处可见,在数据的密集型传输中文件压缩是一项重要的实用性技术.例如:较大文件的下载,传输等.常见的文件压缩工具有winRAR,2345好压,快压(KuaiZip)等,这些工具已经开发的相当牛逼,但是作为入门级的程序员来说,不能只停留在观摩的立场上,扮演使用者的角色.有必要深入了解其底层的基础实现方式,掌握基础的文件压缩原理,所以在此将其视为一个小型项目列出,以供大家交流探讨,相互学习.... ★在此之前,先来说说什么是文件压缩,用以抛出一个基