zoukankan      html  css  js  c++  java
  • 哈夫曼树

    哈夫曼树

    给定一个文本 假定是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 }

    最终效果:

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

    落霞与孤鹜齐飞,秋水共长天一色
  • 相关阅读:
    mfc中的_T
    zmq的send
    c++内存相关函数
    如何运行linux shell程序
    Dockfile中的命令如何在.sh中执行
    Linux 错误: $' ': command not found
    实战ZeroMQ的PUSH/PULL推拉模式
    Servlet笔记
    进程控制块(PCB)
    Makefile规则介绍
  • 原文地址:https://www.cnblogs.com/star-and-me/p/7910046.html
Copyright © 2011-2022 走看看