• 数据结构 赫夫曼树及其应用 c++


    带权路径长度最下的称为赫夫曼树(HuffmanTree);

    赫夫曼编码

    在传送电文的时候希望,电文的总长度尽可能的短。可以做出这样的设计,对电文中的字符设计不同长度的编码,且让出现次数较多的字符采用尽可能短的编码。为了区分不同的编码,则必须任何一个字符的编码都不是另外一个编码的前缀。

    赫夫曼树的构造方法

    1. 根据给定的n个权值{w1,w2,...,wn}构成n棵二叉树集合F={T1, T2, T3....},其中每棵二叉树Ti中只有一个带权为wi的根节点。
    2. 在F中选取两颗根节点的权值最小的树作为左右孩子构建一颗新树,且新树的根节点的权值为其左右树上根节点的权值和
    3. 在F中删除这两棵树(即标记为已访问),并在F中添加新树
    4. 重复2,3直到F中只有一棵树,就得到了赫夫曼树

    用w=[5,29,7,8,14,23,3,11]为例

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    5 29 7 8 14 23 3 11              

    1.找到权值最小的两个节点1,7,构成一颗新树,把新树添加到森林中,删除这两棵树

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    5 29 7 8 14 23 3 11  8            

    2.重复以上过程,红色背景表示已经访问过,再次找最小权值的时候,不再考虑这些节点

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    5 29 7 8 14 23 3 11  8  15          
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    5 29 7 8 14 23 3 11  8  15  19        
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    5 29 7 8 14 23 3 11 8 15  19 29       
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    5 29 7 8 14 23 3 11  8  15  19  29 42     
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    5 29 7 8 14 23 3 11  8  15 19   29  42  58  
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    5 29 7 8 14 23 3 11  8  15 19   29  42  58  100

    赫夫曼树中没有度为1的结点,则一棵有n个叶子结点的赫夫曼树一共有2*n-1个结点,可以用一个大小为2*n-1的数组来储存赫夫曼树。赫夫曼树构成后,为求编码需要从叶子结点出发找到一条从叶子结点到根的路径;为了译码则需要相反的路径;则对每个结点而言既要知道它双亲的信息,又要知道孩子结点的信息。

     1 #include<iostream>
     2 #include<cstring>
     3 using namespace std;
     4 /*
     5     author: Lai XingYu
     6       date: 2018/5/17
     7   describe: HuffmanCode
     8 */
     9 typedef struct{
    10     unsigned int weight;
    11     unsigned int parent, lchild, rchild;
    12     bool vis;    //标识该节点是否被访问过,方便找剩下树中权重最小的两棵树
    13 }HTNode, *HuffmanTree;
    14 
    15 typedef char** HuffmanCode;
    16 
    17 void select(HuffmanTree HT, int pos, int& s1, int& s2){
    18     int j;
    19     s1 = s2 = 0;
    20     for(j=1; j<=pos; j++){//找到最小值
    21         if(!HT[j].vis && (s1==0 || HT[s1].weight>HT[j].weight)) s1 = j;
    22     }
    23     for(j=1; j<=pos; j++){//找到次小值
    24         if(j!=s1 && !HT[j].vis && (s2==0 || HT[s2].weight>HT[j].weight)) s2=j;
    25     }//标识为已访问
    26     HT[s1].vis=1;
    27     HT[s2].vis=1;
    28 }
    29 
    30 /*
    31     HC:用来保存生成的huffman code
    32     n: 需要编码字符个数
    33     HT:huffman 树
    34     所有数组中的第一个空间都不使用
    35 */
    36 void HuffmanCoding(HuffmanTree& HT, HuffmanCode& HC, int* w, int n){
    37     if(n<=1) return; //一位字符不需要进行编码
    38     int m = 2*n-1, i;
    39     HT = new HTNode[m+1];
    40     HTNode *p = HT+1;
    41     for(i=1; i<=n; i++){//初始化
    42         HTNode temp = {*w, 0, 0, 0, 0};
    43         *p = temp;
    44         w++;
    45         p++;
    46     }
    47     for(i=n+1; i<=m; i++){
    48         HTNode temp = {0, 0, 0, 0, 0};
    49         *p = temp;
    50         p++;
    51     }
    52     int s1, s2;
    53     for(i=n+1; i<=m; i++){//建立赫夫曼树
    54         select(HT, i-1, s1, s2);                //找未被访问过的权重最小的两个结点的位置
    55         HT[i].lchild = s1; HT[i].rchild = s2;    //把这两个结点作为当前结点的孩子
    56         HT[s1].parent = i; HT[s2].parent = i;    //自然这两个孩子的双亲是i
    57         HT[i].weight = HT[s1].weight + HT[s2].weight;    
    58     }
    59     
    60     HC = new char*[n+1];
    61     char *cd = new char[n];
    62     cd[n-1] = '';
    63     for(i=1; i<=n; i++){//生成编码
    64         int start = n-1, c=i, f=HT[i].parent;
    65         for( ; f!=0; c=f, f=HT[f].parent){    //找到一条从叶子结点到根结点的路径就能求到该字符的编码
    66             if(HT[f].lchild==c) cd[--start] = '0';//左结点表示0
    67             else cd[--start] = '1';//右边节点表示1
    68         }
    69         HC[i] = new char[n-start];
    70         strcpy(HC[i], &cd[start]);
    71 }
    72         delete(cd);
    73 }
    74 
    75 int main(){
    76     HuffmanTree HT;
    77     HuffmanCode HC;
    78     int w[]={5,29,7,8,14,23,3,11};
    79     int n = 8;
    80     HuffmanCoding(HT, HC,  w,  n);
    81     for(int i=1; i<=n; i++) cout<<i<<" "<<HC[i]<<endl;
    82 return 0;}
    有疑惑或者更好的解决方法的朋友,可以联系我,大家一起探讨。qq:1546431565
  • 相关阅读:
    Greedy Gift Givers 贪婪的送礼者
    USACO 1.1.3 Friday the Thirteenth 黑色星期五
    Prime Matrix(暴力出奇迹)
    博弈论
    好车牌
    C语言中动态内存的分配(malloc,realloc)
    Saruman's Army(贪心)
    Python练习——循环2
    Fox and Number Game
    Repair the Wall (贪心)
  • 原文地址:https://www.cnblogs.com/mr-stn/p/9054143.html
Copyright © 2020-2023  润新知