Huffman编码

  1 #define _CRT_SECURE_NO_WARNINGS
  2 #include <iostream>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <cstdlib>
  6 #include <string>
  7 using namespace std;
  8 
  9 struct Node {
 10     char character;
 11     unsigned int weight;
 12     unsigned int parent;
 13     unsigned int lchild;
 14     unsigned int rchild;
 15 };
 16 
 17 Node *HT = NULL;
 18 char **HC = NULL;
 19 int n = 0;
 20 
 21 void CreatHuffmanTree(void);
 22 void CodeHuffman(void);
 23 void Encode(void);
 24 void Decode(void);
 25 void Free(void);
 26 void Select(const int len, int &a, int &b);
 27 int Search(const char &key);
 28 
 29 int main(void)
 30 {
 31     freopen("cin.txt", "r", stdin);
 32     freopen("cout.txt", "w", stdout);
 33     while (cout << "请输入字符个数:\n", cin >> n) {    //    n>=2
 34         getchar();                //    吸收回车,防止空格字符的输入异常
 35 
 36         CreatHuffmanTree();        //    建哈夫曼树
 37 
 38         CodeHuffman();            //    为每个字符编码
 39 
 40         Encode();                //    为明文编码
 41 
 42         Decode();                //    从密文译码
 43 
 44         Free();                    //    释放动态分配的空间
 45     }
 46     system("pause");// 有用?
 47     return 0;
 48 }
 49 
 50 void CreatHuffmanTree(void)
 51 {
 52     // weight存放n个字符的权值(均>0),构造哈夫曼树HT,
 53     // 并求出n个字符的哈夫曼编码HC
 54     if (n <= 1)
 55         return;
 56     int m = 2 * n - 1;
 57 
 58     HT = (Node *)malloc((m + 1) * sizeof(Node));    //    0号单元未用
 59     if( HT == NULL) {
 60         cerr << "Allocate failed!" << endl;
 61         exit(OVERFLOW);
 62     }
 63     memset(HT, 0, (m + 1) * sizeof(Node));
 64 
 65     cout << "请输入各字符及其权值:" << endl;
 66     for (int i = 1; i <= n; i++) {
 67         HT[i].character = getchar();
 68         cin >> HT[i].weight;                        //    输入字符及权值的信息
 69         getchar();
 70     }
 71     cout << n << "个字符及其权值:" << endl;
 72     for (int i = 1; i <= n; i++) {
 73         printf("%c(%3d) ", HT[i].character, HT[i].weight);
 74         if (i % 10 == 0)
 75             cout << endl;
 76     }
 77     cout << endl;
 78 
 79     /*    printf("\n哈夫曼树的构造过程如下所示:\n");
 80     printf("HT初态:\n  结点  weight  parent  lchild  rchild");
 81     for (int i = 1; i <= m; i++)
 82     printf("\n%4d%8d%8d%8d%8d", i, HT[i].weight, HT[i].parent, HT[i].lchild, HT[i].rchild);
 83     printf("    按回车键,继续 ...");
 84     //    getchar();*/
 85 
 86     for (int i = n + 1; i <= m; i++) {
 87         // 在HT[1..i-1]中选择parent为0且weight最小的两个结点,
 88         // 其序号分别为s1和s2。
 89         int s1(0);
 90         int s2(0);
 91         Select(i - 1, s1, s2);
 92         HT[s1].parent = i;
 93         HT[s2].parent = i;
 94         HT[i].lchild = s1;
 95         HT[i].rchild = s2;
 96         HT[i].weight = HT[s1].weight + HT[s2].weight;
 97 
 98         /*        printf("\nselect: s1=%d   s2=%d\n\n", s1, s2);
 99         printf("  结点  weight  parent  lchild  rchild");
100         for (int j = 1; j <= i; j++)
101         printf("\n%4d%8d%8d%8d%8d", j, HT[j].weight, HT[j].parent, HT[j].lchild, HT[j].rchild);
102         printf("    按回车键,继续 ...");
103         //        getchar();*/
104     }
105 }
106 
107 void CodeHuffman(void)
108 {
109     //--- 从叶子到根逆向求每个字符的哈夫曼编码 ---
110     HC = (char **)malloc((n + 1) * sizeof(char *));            //    指针数组
111     if (HC == NULL) {
112         cerr << "Allocate failed!" << endl;
113         exit(OVERFLOW);
114     }
115     memset(HC, 0, (n + 1) * sizeof(char *));                //    0号单元未用
116 
117     char *cd = (char *)malloc(n * sizeof(char));            // 分配求编码的工作空间
118     if (cd == NULL) {
119         cerr << "Allocate failed!" << endl;
120         exit(OVERFLOW);
121     }
122     memset(cd, 0, n * sizeof(char));                        // 编码结束符。
123 
124     for (int i = 1; i <= n; ++i) {                            // 逐个字符求哈夫曼编码
125         int start = n - 1;                                    // 编码结束符位置
126         unsigned int c(0);
127         unsigned int f(0);
128         for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent) {                                                        
129             if (HT[f].lchild == c)                            // 从叶子到根逆向求编码
130                 cd[--start] = '0';
131             else
132                 cd[--start] = '1';            
133         }
134 
135         HC[i] = (char *)malloc((n - start) * sizeof(char));    // 为第i个字符编码分配空间
136         if (HC[i] == NULL) {
137             cerr << "Allocate failed!" << endl;
138             exit(OVERFLOW);
139         }
140 
141         strcpy(HC[i], &cd[start]);                            // 从cd复制编码(串)到HC
142     }
143     free(cd);
144     cd = NULL;
145 
146     printf("\n\n各字符的哈夫曼编码如下:\n");
147     for(int i = 1; i <= n; i++) {
148         printf("%c(%3d): %s\n" ,HT[i].character, HT[i].weight, HC[i]);
149     }
150 }
151 
152 void Encode(void)
153 {
154     cout << "请输入报文:" << endl;
155     string str;
156     getline(cin, str);
157     for (unsigned int i = 0; i < str.size(); i++) {
158         int loc = Search(str[i]);
159         cout << HC[loc] << endl;
160     }
161     cout << endl;
162 }
163 
164 void Decode(void)
165 {
166     cout << "请输入密文:" << endl;
167     string str;
168     cin >> str;
169     for (unsigned int i = 0; i < str.size();) {
170         int cursor = 2 * n - 1;
171         while (HT[cursor].lchild != 0 && HT[cursor].rchild != 0) {    //    全非0
172             switch (str[i++]) {
173 
174             case '0':
175                 cursor = HT[cursor].lchild;
176                 break;
177 
178             case '1':
179                 cursor = HT[cursor].rchild;
180                 break;
181 
182             default:
183                 cerr << "Input error!" << endl;
184                 exit (1);
185             }
186         }
187         if (!(HT[cursor].lchild == 0 && HT[cursor].rchild == 0)) {    //    此时应是全0
188             cerr << "Input error!" << endl;
189             exit (1);            
190         }
191         cout << HT[cursor].character << endl;
192     }
193 }
194 
195 void Free(void)
196 {
197     free(HT);    //    释放动态分配的空间
198     HT = NULL;
199     for(int i = 1; i <= n; i++) {
200         free(HC[i]);
201         HC[i] = NULL;
202     }
203     free(HC);
204     HC = NULL;
205 }
206 
207 void Select(const int len, int &a, int &b)
208 {
209     // 在HT[1..len]中选择parent为0且weight最小的两个结点,
210     // 其序号分别为a和b。
211     for (int i = 1; i <= len; i++) {
212         if (HT[i].parent == 0) {
213             a = i;
214             break;
215         }
216     }
217     for (int i = a + 1; i <= len; i++) {
218         if (HT[i].parent == 0) {
219             b = i;
220             break;
221         }
222     }
223     if (HT[a].weight > HT[b].weight)    //    保持a的始终小于b的,有序
224         swap(a, b);
225     for (int i = max(a, b) + 1; i <= len; i++) {
226         if (HT[i].parent == 0) {
227             if (HT[i].weight > HT[b].weight)
228                 continue;
229             else if (HT[i].weight < HT[a].weight) {
230                 b = a;
231                 a = i;
232             }
233             else
234                 b = i;
235         }
236     }
237     if ( !(HT[a].parent == 0 && HT[b].parent == 0) ) {
238         cerr << "Error!" << endl;
239         exit(1);
240     }
241 }
242 
243 int Search(const char &key)        //    找到key在HT中的下标,找不到则返回0
244 {
245     HT[0].character = key;        //    哨兵,顺序查找
246     int i;
247     for (i = n; HT[i].character != key; --i);
248     if (i == 0) {
249         cerr << "Inexistence!" << endl;
250         exit(1);
251     }
252     return i;
253 }
254 
255 /*
256 cin.txt:
257 27
258   186
259 a 64
260 b 13
261 c 22
262 d 32
263 e 103
264 f 21
265 g 15
266 h 47
267 i 57
268 j 1
269 k 5
270 l 32
271 m 20
272 n 57
273 o 63
274 p 15
275 q 1
276 r 48
277 s 51
278 t 80
279 u 23
280 v 8
281 w 18
282 x 1
283 y 16
284 z 1
285 this program is my favorite
286 */

 输出:

 

请输入字符个数:
请输入各字符及其权值:
27个字符及其权值:
(186) a( 64) b( 13) c( 22) d( 32) e(103) f( 21) g( 15) h( 47) i( 57)
j( 1) k( 5) l( 32) m( 20) n( 57) o( 63) p( 15) q( 1) r( 48) s( 51)
t( 80) u( 23) v( 8) w( 18) x( 1) y( 16) z( 1)


各字符的哈夫曼编码如下:
(186): 111
a( 64): 1010
b( 13): 100000
c( 22): 00000
d( 32): 10110
e(103): 010
f( 21): 110011
g( 15): 100010
h( 47): 0001
i( 57): 0110
j( 1): 1100001000
k( 5): 11000011
l( 32): 10111
m( 20): 110010
n( 57): 0111
o( 63): 1001
p( 15): 100001
q( 1): 1100001010
r( 48): 0010
s( 51): 0011
t( 80): 1101
u( 23): 00001
v( 8): 1100000
w( 18): 110001
x( 1): 1100001011
y( 16): 100011
z( 1): 1100001001
请输入报文:
1101
0001
0110
0011
111
100001
0010
1001
100010
0010
1010
110010
111
0110
0011
111
110010
100011
111
110011
1010
1100000
1001
0010
0110
1101
010

请输入密文:
请按任意键继续. . .
请输入字符个数:

 

 

 

 

 

 

考研机试题

 

  1 /**************************************
  2 created:    2014/03/14
  3 filename:    13_07_huffman.cpp
  4 purpose:    Huffman encode
  5 **************************************/
  6 
  7 #pragma warning(disable: 4786)
  8 #include <iostream>
  9 #include <queue>
 10 #include <string>
 11 #include <cmath>
 12 #include <map>
 13 #include <cassert>
 14 using namespace std;
 15 
 16 struct Node {
 17     double weight;
 18     Node *left;
 19     Node *right;
 20     int num;    // 记录输入时的次序,为了按输入顺序输出
 21     
 22     Node(double w = 0.0, int n = -1) : weight(w), left(NULL), right(NULL), num(n) {}
 23     
 24     bool is_leaf() const {
 25         return NULL == left && NULL == right;
 26     }
 27 };
 28 
 29 struct Cmp {
 30     bool operator()(Node *a, Node *b) const {
 31         return a->weight > b->weight;
 32     }
 33 };
 34 
 35 /*
 36 ** 使两个结点成为兄弟,返回他们的父亲的地址
 37 */
 38 Node * conjoin(Node *left, Node *right) {
 39     Node *father = new Node(left->weight + right->weight);    // 这里产生的结点都是分支结点
 40     father->left = left;
 41     father->right = right;
 42     
 43     return father;
 44 }
 45 
 46 /*
 47 ** 根据优先队列建 Huffman 树
 48 */
 49 Node * create_tree(priority_queue<Node *, vector<Node *>, Cmp> &Q) {
 50     while (1 != Q.size()) {
 51         Node *left = Q.top();
 52         Q.pop();
 53         Node *right = Q.top();
 54         Q.pop();
 55         Q.push(conjoin(left, right));
 56     }
 57     Node *tree = Q.top();
 58     Q.pop();
 59     
 60     return tree;
 61 }
 62 
 63 /*
 64 ** 前序遍历 Huffman 树得到叶子的编码存储在 code_map 中
 65 */
 66 void get_code(Node const *const tree, const string str, map<int, string> &code_map) {
 67     if (NULL == tree) {
 68         return ;
 69     }
 70     if (tree->is_leaf()) {
 71         code_map[tree->num] = str;
 72         return ;
 73     }
 74     get_code(tree->left, str + "0", code_map);
 75     get_code(tree->right, str + "1", code_map);
 76 }
 77 
 78 /*
 79 ** 后序遍历释放树
 80 */
 81 void free_tree(Node *&tree) {
 82     if (NULL == tree) {
 83         return ;
 84     }
 85     
 86     free(tree->left);
 87     free(tree->right);
 88     delete tree;
 89     tree = NULL;
 90 }
 91 
 92 int main(int argc, char **argv) {
 93     FILE *in_stream = freopen("7.in", "r", stdin);
 94     if (NULL == in_stream) {
 95         cerr << "Can not open file." << endl;
 96         exit(1);
 97     }
 98     FILE *out_stream = freopen("7.out", "w", stdout);
 99     
100     priority_queue<Node *, vector<Node *>, Cmp> Q;
101     double elem;
102     int n;
103     cin >> n;
104     int i;
105     for (i = 0; i < n; ++i) {
106         cin >> elem;
107         Q.push(new Node(elem, i));
108     }
109     
110     Node *tree = create_tree(Q);        // 根据输入数据建 Huffman 树
111     assert(Q.empty());
112     map<int, string> code_map;
113     get_code(tree, string(), code_map);    // 根据 Huffman 树获取 Huffman 编码
114     
115     for (i = 0; i < n; ++i) {
116         cout << code_map[i] << endl;
117     }
118     
119     free_tree(tree);
120     
121     fclose(in_stream);
122     fclose(out_stream);
123     
124     return 0;
125 }
126 
127 /* 7.in
128 4
129 0.3 0.1 0.4 0.2
130 */

 

你可能感兴趣的:(Huffman编码)