一步两步学算法之哈夫曼编码(最优二叉树)

比较难理解的 都打了备注了

  1 #include "stdio.h"
  2 #include "stdlib.h"
  3 #include "string.h"
  4 char alphabet[]={‘A‘,‘B‘,‘C‘,‘D‘};
  5 typedef struct
  6 {
  7     int weight;        //权值
  8     int parent;        //父节点序号
  9     int left ;
 10     int right;
 11 }HuffmanTree;
 12
 13 typedef char *HuffmanCode;  //Huffman编码指针
 14 void SelectNode (HuffmanTree *ht,int n,int *bt1,int *bt2)
 15 //从n个节点中选择parent节点为0,权重最小的两个节点
 16 {
 17     int i;
 18     HuffmanTree *ht1,*ht2,*t;
 19     ht1=ht2=NULL;
 20     for(i=1;i<=n;i++)
 21     {
 22         if(!ht[i].parent)                //父节点为空
 23         {
 24             if(ht1==NULL)
 25             {
 26                 ht1=ht+i;                //
 27                 continue;
 28             }
 29             if(ht2==NULL)
 30             {
 31                 ht2=ht+i;
 32                 if(ht1->weight>ht2->weight)
 33                 {
 34                     t=ht2;
 35                     ht2=ht1;
 36                     ht1=t;            //让ht1指向最小节点 ht2指向第二小
 37                 }
 38                 continue;
 39             }
 40             if(ht1 &&ht2)
 41             {
 42                 if(ht[i].weight<=ht1->weight)
 43                 {
 44                     ht2=ht1;                    //如果还有比ht1更小的则把ht1赋给ht2 ,ht1继续等于最小
 45                     ht1=ht+i;
 46                 }
 47                 else if(ht[i].weight<ht2->weight){
 48                     ht2=ht+i;                        //没有比ht1更小的 但有比ht2小的
 49                 }
 50             }
 51         }
 52     }
 53     if(ht1>ht2){                    //按数组最初的位置排序
 54         *bt2=ht1-ht;
 55         *bt1=ht2-ht;
 56     }
 57     else
 58     {
 59         *bt1=ht1-ht;
 60         *bt2=ht2-ht;
 61     }
 62 }
 63 void CreateTree(HuffmanTree *ht,int n,int *w)
 64 {
 65     int i,m=2*n-1;    //总节点数
 66     int bt1,bt2;
 67     if(n<=1)
 68         return ;
 69     for(i=1;i<=n;++i)
 70     {
 71         ht[i].weight=w[i-1];
 72         ht[i].parent=0;
 73         ht[i].left=0;
 74         ht[i].right=0;
 75     }
 76     for(;i<=m;++i)
 77     {
 78         ht[i].weight=0;
 79         ht[i].parent=0;
 80         ht[i].left=0;
 81         ht[i].right=0;
 82     }
 83     for(i=n+1;i<=m;++i)
 84     {
 85         SelectNode(ht,i-1,&bt1,&bt2);
 86         ht[bt1].parent=i;
 87         ht[bt2].parent=i;
 88         ht[i].left=bt1;
 89         ht[i].right=bt2;
 90         ht[i].weight=ht[bt1].weight+ht[bt2].weight;
 91     }
 92 }
 93
 94
 95 void HuffmanCoding(HuffmanTree *ht,int n,HuffmanCode *hc)
 96 {
 97     char *cd;
 98     int start,i;
 99     int current,parent;
100     cd=(char*)malloc(sizeof(char)*n);
101     cd[n-1]=‘\0‘;
102     for(i=1;i<=n;i++)
103     {
104         start=n-1;
105         current=i;                            //获得当前节点序号
106         parent=ht[current].parent;            //获得当前节点父亲的序号
107         while(parent)            //当父节点不为空
108         {
109             if(current==ht[parent].left)    //若当前节点是父亲的左节点
110                 cd[--start]=‘0‘;            //字符最后编码为0 注意这个编码是逆序的 最后其实根节点
111             else
112                 cd[--start]=‘1‘;
113             current=parent;                    //从当前节点向根节点寻找
114             parent=ht[parent].parent;
115         }
116         hc[i-1]=(char*)malloc(sizeof(char)*(n-start));    //分配保存编码的内存
117         strcpy(hc[i-1],&cd[start]);                        //复制生成的编码
118     }
119     free(cd);
120 }
121
122 void Encode(HuffmanCode *hc,char *alphabet,char *str,char *code)
123 {
124     int len=0,i=0,j;
125     code[0]=‘\0‘;
126     while(str[i])
127     {
128         j=0;
129         while(alphabet[j]!=str[i])   //搜索字母在编码表的位置
130             j++;
131         strcpy(code+len,hc[j]);        //字母在叶节点的编号到根节点的编号全部复制给code
132         len=len+strlen(hc[j]);        // 扩大len的长度(也就是节点深度)
133         i++;
134     }
135     code[len]=‘\0‘;
136 }
137
138 void Decode(HuffmanTree *ht,int m,char *code,char *alphabet,char *decode)//解码
139 {
140     int    position=0,i,j=0;
141     m=2*m-1;
142     while(code[position])
143     {
144         for(i=m;ht[i].left &&ht[i].right;position++ )
145         {
146             if(code[position]==‘0‘)
147                 i=ht[i].left;
148             else
149                 i=ht[i].right;
150         }
151         decode[j]=alphabet[i-1];
152         j++;
153     }
154     decode[j]=‘\0‘;
155 }
156 int main()
157 {
158     int i,n=4,m;
159     char test[]="DBDBDABDCDADBDADBDADACDBDBD";
160     char code[100],code1[100];
161
162     int w[]={5,7,2,13};
163     HuffmanTree *ht;
164     HuffmanCode *hc;
165     m=2*n-1;
166     ht=(HuffmanTree *)malloc((m+1)*sizeof(HuffmanTree));
167     if(!ht)
168     {
169         printf("分配内存失败\n");
170         exit(0);
171     }
172     CreateTree(ht,n,w);
173     HuffmanCoding(ht,n,hc);
174     for(i=1;i<=n;i++)
175         printf("字母:%c,权重:%d,编码:%s\n",alphabet[i-1],ht[i].weight,hc[i-1]);
176     Encode(hc,alphabet,test,code);
177     printf("\n字符串:\n%s\n转换后:\n%s\n",test,code);
178     Decode(ht,n,code,alphabet,code1);
179     printf("\n编码:\n%s\n转换后:\n%s\n",code,code1);
180
181     return 0;
182 } 
时间: 2024-11-04 12:36:34

一步两步学算法之哈夫曼编码(最优二叉树)的相关文章

算法学习-哈夫曼编码(c++实现)

哈夫曼编码 哈夫曼编码虽然简单,但是是一个非常重要的编码方式,它解决了数据存储的一个非常重要的问题:压缩!它的编码方式是最优的,无损的,尤其在图像中使用的非常多.下面讲下它的原理. 编码方式 哈夫曼编码的构造是依据权值的大小来实现的.首先根据权值构造哈夫曼树,然后对哈夫曼树进行逆向遍历,从而找到每个节点的编码方式. 例如: abbcccdddde这个是一个字符串,一共有5个字符.每个字符的权值就是出现的频率,那么a就是1,b权值为2,c的权值为3,d的权值为4,e的权值为1.在普通的编码方式中,

贪心算法应用-哈夫曼编码

哈夫曼编码应用于数据文件和图像压缩的编码方式.其压缩率通常在20%~90%之间.在进行远距离通信时,通常需要把将要传送的文字转换为由二进制字符组成的字符串,并使要传送的电文总长度尽可能的短.显然只要将点文章出现次数多的字符采用尽可能短的编码,就可以减少要传送的电文总长度. 哈夫曼编码的核心思想: (1)每一个字符用一个0,1串作为其代码,并要求任意一个字符的代码都不是其他字符代码的前缀. (2)用字符在文件中出现的频率来建立一个用0,1串表示各字符的最优表示方式,即使出现频率高的字符获得较短编码

贪心算法-霍夫曼编码

霍夫曼编码是一种无损数据压缩算法.在计算机数据处理中,霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现机率的方法得到的,出现机率高的字母使用较短的编码,反之出现机率低的则使用较长的编码,这便使编码之后的字符串的平均长度.期望值降低,从而达到无损压缩数据的目的.例如,在英文中,e的出现机率最高,而z的出现概率则最低.当利用霍夫曼编码对一篇英文进行压缩时,e极有可能用一个比特来表示,而z则可能花去25个比特(不是26).用普通的表示方法时,每个

信源编码算法(费诺编码&amp;&amp;哈夫曼编码)

信源编码算法 费诺编码 Fano coding 哈夫曼编码 Huffman coding 费诺编码 编码步骤 将信源符号按照其概率大小,从大到小排列: 将这一组信源符号分成概率之和尽可能接近或者相等的一组(即两组分别的概率和之间的差尽可能小!): 将上面一组符号编码成0,下面一组编码成1,反之亦可: 将已经分好的组重复步骤2,3,直到不能再进行分组为止: 从左到右一次写出码字. 费诺编码演示 已知: 编码过程为: 哈夫曼编码 Huffman coding 编码步骤 将信源符号按照概率大小从大到小

【算法总结】哈夫曼树和哈夫曼编码

一.哈夫曼树 1. 哈夫曼树也称最优二叉树. 叶子节点的权值是对叶子节点赋予的一个有意义的数值量. 设二叉树具有 n 个带权值的叶子结点,从根节点到各个叶子结点的路径长度与相应叶子结点权值的乘积之和叫做二叉树的带权路径长度. 给定一组具有确定权值的叶子结点,可以构造处不同的二叉树,将其中带权路径长度最小的二叉树称为哈夫曼树. 2. 基本思想: 初始化:由给定的 n 个权值 $\left\{ \omega_{1},\omega_{2},\cdots ,\omega_{n}\right\}$构造 n

两个队列+k叉哈夫曼树 HDU 5884

1 // 两个队列+k叉哈夫曼树 HDU 5884 2 // camp题解: 3 // 题意:nn个有序序列的归并排序.每次可以选择不超过kk个序列进行合并,合并代价为这些序列的长度和.总的合并代价不能超过TT, 问kk最小是多少. 4 // . 5 // 题解:首先二分一下这个kk.然后在给定kk的情况下,这个代价其实就是kk叉的哈夫曼树问题.因此直接套用哈夫曼树的堆做法即可.复杂度O(nlog^2n) 6 // ?,这样优化一下读入是可以卡过去的. 7 // 然后主代码手表示,利用合并的单调

哈夫曼编码算法思想总结

1构建哈夫曼树. (利用队列的数据结构,不断获取最小的两个,退出队列并使之成为新节点的左右子树.然后将新节点插入队列.如此循环……) 根据用户输入的字符串,统计每个字符出现次数.设置权重.建立队列.队列中的节点是二叉树的节点(有左指针,和右指针). 建新的结点,左右指针指向队列的最后两个(那两个退出队列).然后插入队列.如此循环,就可以建立哈夫曼树. 2为每个字符编码. 节点的左为0,右为1. code(*node) { //叶节点 如果(node->left==null && no

一步两步学算法之树的遍历 非递归实现

递归的程序其实我觉得可读性较高  但是执行效率低下 为了做一道PAT的题 去理解了下非递归实现树的遍历 用一个栈来实现 先序遍历 先访问节点 再把节点push进栈 再访问 再push 直到next=NULL 然后pop出一个节点 也就是弹出一个节点 访问它的右边 再弹出 在访问 中序遍历 把左边节点全部push进栈 然后弹出 访问中间 再访问右边  再弹出 一直循环 后序遍历 比较难理解  要入两次栈才能访问 先左边全部入栈  栈顶是左边的元素 此书不能访问 因为右边还没入栈 下面给出先序和后序

一步两步学算法之图的广度搜索

bfs利用队列搜索    详细看代码 #define VERTEX_MAX 26 //图的最大定点数 #define MAXVALUE 32767 //最大值 #include "stdio.h" #define QUEUE_MAXSIZE 10 //队列最大容量 typedef struct { char Vertex[VERTEX_MAX]; //保存定点信息的数组 int Edges[VERTEX_MAX][VERTEX_MAX]; //边的权 int IsTrav[VERTEX