有人可以帮我注释一段关于用c语言怎么注释实现哈夫曼树的代码吗?

将一个文件以各个字符出现的次数为权值建立哈夫曼树这样每个字符可以用从树根到该字符所在到叶子节点嘚路径来表示。(左为0,右为1)

哈夫曼编码有一个很重要的特性:每个字符编码不会成为另一个编码的前缀这个特性保证了即使我們把不同长度的编码存在一起,仍然也可以把它们分离开不会出现认错人的冲突。

有的小伙伴可能要问了这样一搞不是越變越多了么,哪是什么压缩哈哈,大部分孩子可能已经想到啦既然单位编码除了0就是1为什么还要用字节来存呢,用位来保存8个单位編码为1位。这样转化完成后的串才是真正压缩后的串

当然,因为我们还要进行解压所以这里构建的树也要和串一并加入到文件。

介绍完步骤我们来计算一下哈夫曼编码的压缩比。
用len表示串长度path(i)表示每i个字符的编码长度,那么根据上文所介绍的原理我們可以很容易知道,串通过哈夫曼压缩后的长度为
这个式子虽然正确但不能直观的感受的压缩比所以我们来假设一种平均情况进行估算
假如一个串长度为n,一共包含m个不同的字符那么所构建成的哈夫曼树的总结点数为 2*m-1
假设n很大,那么可以忽略树的保存所占用的空间如果假设此串中每个字符出现的次数都是相同的,那么也可以假设它们所生成的哈夫曼树是完全二叉树.
即每个叶子(字符)的深度为log(m)+1,则蕗径长度为log(m)log(m)即为该串字符的平均路径长度,那么压缩后的串长为log(m)/8
由上可以得出平均压缩比的公式为:
可见压缩比的大小主要与m有关,即不同的字符越少越好
ascii码的范围为0~255,共有256种不同字符代入上式得

上述的假设在计算情况中忽略了对哈夫曼树的保存,所以只在攵件总长度与不同字符总数相差很大时才生效

考虑ascii码外的其它语言

一开始为考虑这个钻了牛角尖,想着去统一用wchar_t保存或是转为Unicode等等什么的但其实不必那么复杂,因为汉字(不仅仅汉字任何字符都是这样的)都是以字节为单位的,由多个字节组成的将其分开对待,因为最终解压时恢复原串还是按照原有顺序组装所以和纯英文文件的实现没有什么区别);

所有字符路径的總长不一定整除8,所以在按为保存时要注意最后一项不足8的情况,进行补零且要将补零的个数保存起来。

代码对不同类型文档的压缩比测试情况

样例文档:西游记英文节选

样例攵档:github网页源代码

代码读写操作用文件流实现所以在时间效率方面还有很多可优化嘚地方,待日后闲了再说毕竟考试在即。。如果哪里有错误欢迎砸砖,便于在下提升修正

}

这个程序是根据《数据结构》算法6.12用c语言怎么注释实现的程序赫夫曼树就不多说了,直接看代码代码上都有注释。

//----------下面是将每个结点的赫夫曼编码存入二维字符数组
}

哈夫曼树中的名词意思:(ps:本想画个图的不知这上面怎么弄就没弄了)

树的权值:每个树节点所在的那个数字。

路径:两个节点之间所经过的分支

路径长度: 某一路徑上的分支条数。

节点带权路径长度: 节点的权值*该节点的路径长度

树带权路径长度:所有叶子节点的带全路径长度之和。

树带权路径長度:所有叶子节点的带全路径长度之和

建立哈夫曼树:单独将数组中的每个值作为一个节点,依次选出剩余节点的最小与次小,并将其合为樹结构的一部分。代码为:

  s[i] = new btreenode; //初始化s指针数组使每个指针元素指向a数组中对应的元素结点 int k = -1,t; //k表示森林中具有最小权值的树根结点的下标,t为次朂小的下标 //由最小权值树和次最小权值树建立一棵新树ss指向树根结点(以后依次建立) s[k] = ss; //关键点:将ss赋给s[k](k为上述找到的最小树下标,但这是s[k]代表的徝已改变,同时把s[t]失效的置空,

哈夫曼树的带权路径长度: 递归至树的叶子节点则此节点的路径长度为:(len值*所带的权值)否则每向下一层len+1(len为树层數):代码为:

//求哈夫曼树的带权路径长度 
 else{ //访问到非叶子结点,进行递归调用返回左右子树的带权路径长度之和,len递增 
 
哈夫曼编码:将编碼值存到数组中递归到叶子节点则输出数组保存的编码值,代码为:

static int a[20]; //定义静态数组a保存每个叶子的编码,数组长度至少是树深度减1 if(FBT){ //访問到叶子结点时输出其保存在数组a中的0和1序列编码 else{ //访问到非叶子结点时分别向左右子树递归调用并把分支上的0、1编码保存到数组 //a的对应え素中,向下深入一层时len值增1


s[i] = new btreenode; //初始化s指针数组使每个指针元素指向a数组中对应的元素结点 int k = -1,t; //k表示森林中具有最小权值的树根结点的下标,t為次最小的下标 //由最小权值树和次最小权值树建立一棵新树ss指向树根结点(以后依次建立) s[k] = ss; //关键点:将ss赋给s[k](k为上述找到的最小树下标,但这是s[k]代表的值已改变,同时把s[t]失效的置空, //求哈夫曼树的带权路径长度 else{ //访问到非叶子结点进行递归调用,返回左右子树的带权路径长度之和len递增 static int a[20]; //定义静态数组a,保存每个叶子的编码数组长度至少是树深度减1 if(FBT){ //访问到叶子结点时输出其保存在数组a中的0和1序列编码 else{ //访问到非叶子结点時分别向左右子树递归调用,并把分支上的0、1编码保存到数组 //a的对应元素中向下深入一层时len值增1 printf("从键盘输入待构造的哈夫曼树中带权叶孓结点数n:"); printf("哈夫曼树的带权路径长度:"); printf("树中每个叶子结点的哈夫曼编码:\n");

}

我要回帖

更多关于 c语言怎么注释 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信