哈夫曼树

哈夫曼树

给定一个文本 假定是26个英文字符组成的文本 , 根据每个字符出现的次数进行哈夫曼编码,使得编码后的文本占用空间最小。

编码思路

1:对字母的权值排序 , 从小到大选取2个 , 作为新建父节点的儿子。

2:父节点的值为儿子节点的权值和。

3:把新节点加入集合中。

4:重复上述过程,直到集合为空。

译码过程

从根节点开始,向叶子节点搜索,规定向左为1,向右为0,到达根节点时的路径就是叶子节点的编码。

代码实现:将每个叶子节点放入set中 , 按照权值排序。

每次取出两个节点,新建父节点,链接。

将新节点加入set中。

重复上述操作直到集合为空or只有一个元素。

 1 /***
 2     input : number of every char from a to z from a txt named 2.txt
 3     target: build a huffman tree
 4     output: every char's code
 5 */
 6 #include <bits/stdc++.h>
 7 using namespace std;
 8 
 9 class node      //node
10 {
11 public:
12     int key;
13     char s;
14     node  *left , *right ;
15 };
16 
17 struct comp     //sort for set
18 {
19     bool operator()(node *a,node *b)
20     {
21         return a->key < b->key ;
22     }
23 };
24 int a[30];
25 multiset<node*,comp>contain;
26 node *root;
27 void init()                 // initial nodes in set
28 {
29     contain.clear();
30     for(int i=1;i<=26;i++)
31     {
32         node *ans = new node;
33         ans->left = NULL;
34         ans->right = NULL;
35         ans->key = a[i];
36         ans->s = i+'a'-1;
37         contain.insert(ans);
38     }
39 }
40 
41 node* build()                   //build a huffman tree and return root
42 {
43     multiset<node*,comp>::iterator iter;
44     while(!contain.empty())
45     {
46         int i=0;
47         node *p1 , *p2;
48         iter = contain.begin();
49         p1 = *iter ;
50         contain.erase(iter++);
51         if(iter == contain.end()) return p1;
52         p2 = *iter ;
53         contain.erase(iter);
54 
55         node * father = new node;
56         father ->left = p1;
57         father ->right = p2;
58         father ->s = '#';
59         father ->key = p1->key + p2->key;
60         contain.insert(father);
61     }
62 }
63 
64 void preorder(node *x,string fin)           //get every char's code
65 {
66     if(x==NULL) return ;
67     if(x->s !='#') cout<<x->s<<"  "<<fin<<endl;
68     preorder(x->left,fin+"1");
69     preorder(x->right,fin+"0");
70 }
71 int main()
72 {
73     fstream in("2.txt");
74     for(int i=1;i<=26;i++)
75         in>>a[i];
76     init();
77 
78     multiset<node*,comp>::iterator iter;
79     for(iter = contain.begin();iter!=contain.end();iter++)
80     {
81         cout<<(*iter)->s<<"   "  <<(*iter)->key<<" "<<endl;
82     }
83     root = build();
84     /// build is done
85     /// start to decode
86     preorder(root,"");
87     return 0;
88 }
View Code

使用优先队列实现建树过程,用map<char,string>记录各个字符的编码.

 1 /// 哈夫曼树的节点
 2 class node      //node
 3 {
 4 public:
 5     int key;
 6     char s;
 7     node  *left , *right ;
 8 };
 9 struct cmp
10 {
11     bool operator() (node* a, node *b)
12     {
13         return a->key > b->key;
14     }
15 };
16 
17 priority_queue <node*,vector<node*>,cmp>contain;
18 node *root;
19 /// 初始化,建立叶子节点
20 void init()                 // initial nodes in set
21 {
22     for(int i=1;i<=num;i++)
23     {
24         node *ans = new node;
25         ans->left = NULL;
26         ans->right = NULL;
27         ans->key = a[i];
28         ans->s = b[i];
29         contain.push(ans);
30         //cout<<ans->s<<" "<<ans->key<<endl;
31     }
32 }
33 
34 ///建立哈夫曼树
35 node* build()                   //build a huffman tree and return root
36 {
37     /// 每次从优先队列中取出两个权值最小的节点,创建一个父节点
38     /// 将父节点加入优先队列
39     /// 重复,知道队列中仅有一个元素,该节点就是哈夫曼树的根节点
40     while(!contain.empty())
41     {
42         node *p1 , *p2;
43 
44         p1 = contain.top();
45         contain.pop();
46         if(contain.empty()) return p1;
47         p2 = contain.top() ;
48         contain.pop();
49 
50         node * father = new node;
51         father ->left = p1;
52         father ->right = p2;
53         father ->s = '#';
54         father ->key = p1->key + p2->key;
55         contain.push(father);
56     }
57 }
58 
59 /// 先序遍历哈夫曼树,得到字符的哈夫曼编码
60 void preorder(node *x,string fin)           //get every char's code
61 {
62     if(x==NULL) return ;
63     if(x->s !='#') mp[x->s] = fin;
64     preorder(x->left,fin+"1");
65     preorder(x->right,fin+"0");
66 }
View Code

 附: 图形化输出二叉树的方法

思路: 将二叉树逆时针旋转90度,横着输一个出, 使用中序遍历,递归的记录节点的层数以便输出空格,每访问一个节点输出节点和换行

1 void print_tree(node *x,int num)
2 {
3     if(x==NULL) return ;
4     print_tree(x->right,num+1);
5     for(int i=0;i<num;i++) printf("==");
6     printf("%c
",x->s);
7     print_tree(x->left,num+1);
8 }

最终效果:

凑合着能看出父子关系.没办法,控制台做图形化实在困难,这样的效果已经不错了.

落霞与孤鹜齐飞,秋水共长天一色
原文地址:https://www.cnblogs.com/star-and-me/p/7910046.html