编译环境:Dev-C++

实现哈夫曼编码的贪心算法实现,并分析哈夫曼编码的算法复杂度。


哈夫曼编码贪心算法的原理如下:

该题目求最小编码长度,即求最优解的问题,可分成几个步骤,一般来说, 每个步骤的最优解不一定是整个问题的最优解,然而对于有些问题,局部贪心可以得到全局的最优解。

        贪心算法将问题的求解过程看作是一系列选择,从问题的某一个初始解出发,向给定目标推进。推进的每一阶段不是依据某一个固定的递推式,而是在每一个阶段都看上去是一个最优的决策(在一定的标准下)。不断地将问题实例归纳为更小的相似的子问题,并期望做出的局部最优的选择产生一个全局得最优解。
        贪心算法适用的问题必须满足两个属性:
贪心性质:整体的最优解可通过--系列局部最优解达到,并且每次的选择可以依赖以前做出的选择,但不能依赖于以后的选择。
最优子结构:问题的整体最优解包含着它的子问题的最优解。

贪心算法的基本步骤:
    ①分解:将原问题分解为若干相互独立的阶段。
    ②解决:对于每一个阶段求局部的最优解。
    ③合并:将各个阶段的解合并为原问题的解。

哈夫曼编码实质上是利用最优二叉树原理,求最优前缀码的长度,即平均码长或文件总长最小的前缀编码。计算公式为:

实质上是让权重越大的编码长度越短,权重越小的编码长度越长。


最优调度动态规划算法的实现步骤如下:

本实验的实现分为两步:先建立哈夫曼树,然后求叶节点的编码。

(1)首先第一步是建立哈夫曼树。

设置一个结构数组 HuffNode 保存哈夫曼树中各结点的信息。根据二叉树的性质可知,具有n个叶子结点的哈夫曼树共有 2n-1 个结点,所以数组 HuffNode 的大小设置为 2n-1 。HuffNode 结构中有 weight, lchild, rchild 和 parent 域。其中,weight 域保存结点的权值, lchild 和 rchild 分别保存该结点的左、右孩子的结点在数组 HuffNode 中的序号,从而建立起结点之间的关系。

为了判定一个结点是否已加入到要建立的哈夫曼树中,可通过 parent 域的值来确定。初始时 parent 的值为 -1。当结点加入到树中去时,该结点 parent 的值为其父结点在数组 HuffNode 中的序号,而不会是 -1 了.

(2)第二步是求叶结点的编码。

该过程实质上就是在已建立的哈夫曼树中,从叶结点开始,沿结点的双亲链域回退到根结点,每回退一步,就走过了哈夫曼树的一个分支,从而得到一位哈夫曼码值。由于一个字符的哈夫曼编码是从根结点到相应叶结点所经过的路径上各分支所组成的 0、1 序列,因此先得到的分支代码为所求编码的低位,后得到的分支代码为所求编码的高位码。

(3)算法实现的流程图


调试过程及结果

(1)遇到的问题以及解决方法

难点主要在于两个方面:

一是怎么设置哈夫曼树的结构,我一开始打算使用优先队列来做,但后来求出最短路径后无法进行编码,于是改成了数组存储树。然后遇到的困难是数据结构遗忘知识过多,忘记了一个二叉树的节点应该是2*(n-1)+1=2*n-1。浪费了一些时间,后来又去复习数据结构,最后是用数组建立了树的结构,每个节点包括左右节点,根节点,权重4个元素。

二是求叶子节点的遍历,本质上是遍历树。实际上就是一个递推的过程,不断搜寻他的父节点直到根节点(parent=0),如果位于父节点的左侧则为0,右侧则编码1。

写代码的过程中也遇到了一些小问题:

在输入叶子节点的时候,怎么把空格字符去除

想了许多办法,最开始是写了一个trim函数,先读入字符串,然后去除空格再转换为字符数组,后来发现可以直接在输入的地方加一个if语句直接做判断,舍去读入的空格字符。

(2)程序执行的结果。

 

复杂度分析:

时间复杂度:因为本实验是通过逐个比较来确定左子树和右子树,所以遍历一遍时间复杂度为O(n),共便利O(n-1)次,所以时间复杂度为O(n*n)。

空间复杂度:实验中申请了一个数组表示树,所以空间复杂度为O(2*n-1)。


源代码:

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#define Bit_max 100
#define Value_max 10000
#define Leaf_number_max 5 //叶节点的数量,即要编码的字符的数量(可以修改)
#define Node_number_max Leaf_number_max*2-1 //哈夫曼树总的节点的数量
using namespace std; char* leaf=(char *)malloc(sizeof(char)*Leaf_number_max);//叶子节点
int* leafweight=(int *)malloc(sizeof(int)*Leaf_number_max);//叶子节点的权值 typedef struct{int bit[Bit_max];//字符的哈弗曼编码int length;//字符的哈弗曼编码长度
}HCodeType;
/*因采用自底向上的编码方式,所以事先不知道编码的长度,就统一地设为n-1,从后向前填写编码,start表示编码开始的位置
*/
typedef struct{int bit[Bit_max];int start;
}tmpHCodeType;typedef struct{int weight;int parent;int lchild;int rchild;
}HNodeType;int n=Leaf_number_max;
HNodeType HuffNode[Node_number_max];//定义全局变量和数组自动初始化
HCodeType HuffCode[Leaf_number_max];
tmpHCodeType cd;void Init_Input(){printf("The number of Leaves are : %d\n",Leaf_number_max);puts("The Leaves are : ");for(int i=0;i<Leaf_number_max;++i){scanf("%c",leaf+i);if(*(leaf+i)==' '){scanf("%c",leaf+i);}else{continue;}}puts("The weight of Leaves are : ");for(int i=0;i<Leaf_number_max;++i){scanf("%d",leafweight+i);}
}
void Make_HuffmanTree(){int m1, m2;//m1,m2为构造哈夫曼树不同过程中两个最小权值结点的权值int Index_1, Index_2;//Index_1,Index_2为构造哈夫曼树不同过程中两个最小权值结点在数组中的序号//初始化存放哈夫曼数组的结点for (int i = 0; i < 2 * n - 1; i++){HuffNode[i].weight = 0;HuffNode[i].parent = -1;HuffNode[i].lchild = -1;HuffNode[i].rchild = -1;}//初始化叶子节点的权值for (int i = 0; i < n; i++){HuffNode[i].weight=leafweight[i];}//循环构造哈夫曼树,n个叶子结点需要n-1次构建(将两棵树合并为一棵树)for (int i = 0; i < n - 1; i++){m1 = m2 = Value_max;Index_1 = Index_2 = 0;//新建立的节点的下标是原来的叶子总结点数+i即n+ifor (int j = 0; j < n + i; j++){//规定左儿子的权值比右儿子小if (HuffNode[j].weight < m1&&HuffNode[j].parent == -1){m2 = m1;Index_2 = Index_1;m1 = HuffNode[j].weight;Index_1 = j;} else if (HuffNode[j].weight < m2&&HuffNode[j].parent == -1){m2 = HuffNode[j].weight;Index_2 = j;}}HuffNode[Index_1].parent = n + i;HuffNode[Index_2].parent = n + i;HuffNode[n + i].weight = HuffNode[Index_1].weight + HuffNode[Index_2].weight;HuffNode[n + i].lchild = Index_1;HuffNode[n + i].rchild = Index_2;}
}//采用自底向上的编码方式,该节点若是左儿子,则为0,若为右儿子则为1
void HuffmanCode(){int c, p;for (int i = 0; i < n; i++){cd.start = n - 1;//刚开始无法确定该字符的编码长度,因此统一设为n-1c = i;//当前节点p = HuffNode[c].parent;//当前节点的父节点while (p != -1){if (HuffNode[p].lchild == c){cd.bit[cd.start] = 0;//如果该节点是左儿子}else{cd.bit[cd.start] = 1;//如果该节点是右儿子}--cd.start;c = p;p = HuffNode[c].parent;}int cnt=0;for (int j = cd.start + 1; j < n; j++){HuffCode[i].bit[cnt++] = cd.bit[j];}HuffCode[i].length = cnt;}//打印各个字符的哈弗曼编码for (int i = 0; i < n; i++){printf("The Huffman code of \"%c\" is : ", leaf[i]);for (int j = 0 ; j <HuffCode[i].length ; j++){printf("%d", HuffCode[i].bit[j]);}putchar('\n'); }
}
int main(){Init_Input();Make_HuffmanTree();HuffmanCode();return 0;
}

实现哈夫曼编码(C语言)相关推荐

  1. 信息论 输入概率的哈夫曼编码 C语言

    信息论 哈夫曼编码 C语言 哈夫曼编码是一种效率比较高的变长无失真信源编码方法.哈夫曼编码的编码方法,步骤如下: 将信源符号按概率从大到小的顺序排列,为方便起见,令p(a1)>=p(a2)> ...

  2. 哈夫曼编码c语言论文,哈夫曼编码的实现及应用论文.doc

    哈夫曼编码的实现及应用论文 毕 业 设 计(论文) 题目 哈夫曼编码的实现 及应用 二级学院 数学与统计学院 专 业 信息与计算科学 班 级 学生姓名 张泽欣 学号 指导教师 职称 时 间 目录 摘要 ...

  3. c语言用赫夫曼编码压缩文件,用哈夫曼编码C语言实现文件压缩

    用哈夫曼编码实现文件压缩,C语言编写,简单实用, if(j%8!=0) /*按八位读取*/ { for(f=j%8;f<8;f++) strcat(header[i].bits,"0& ...

  4. 哈夫曼编码c语言实现

    哈夫曼编码的原理看 百度百科 先生成一个哈夫曼树,参考 哈夫曼树c语言实现 生成接近等长码 须要注意的是,为了缩短码长方差,且编出的码更接近于等长码,排序的时候,第一优先级为概率大小,第二优先级为左节 ...

  5. 信息论霍夫曼编码c语言,霍夫曼编码

    <信息论与编码>课程实验报告 姓 名 学 号 单 位 专 业 2014 年 12 月 4 日 实验一 一.实验目的 1.理解信源编码的意义: 2.掌握霍夫曼编码的方法及计算机实现: 二.实 ...

  6. 南邮哈夫曼编码c语言代码_漫画:“哈夫曼编码” 是什么鬼?

    ​在上一期,我们介绍了一种特殊的数据结构 "哈夫曼树",也被称为最优二叉树.没看过的小伙伴可以点击下方链接: 漫画:什么是 "哈夫曼树" ? 那么,这种数据结构 ...

  7. 信息论霍夫曼编码c语言,Huffman 信息论与编码 - 下载 - 搜珍网

    霍夫曼编码/Shiyan4/Shiyan.sln 霍夫曼编码/Shiyan4/Shiyan.suo 霍夫曼编码/Shiyan4/Shiyan.v11.suo 霍夫曼编码/Shiyan4/Shiyan4 ...

  8. c语言递归计算哈夫曼编码,哈夫曼树遍历求WPL和哈夫曼编码C语言--For初学者

    这篇文章使用纯c来写的,实现了生成哈夫曼树.求WPL和生成哈夫曼编码的应用,思路是,先定义一个结构体如下 typedef struct node { int weight; struct node * ...

  9. 二进制哈夫曼编码c语言实现,二进制霍夫曼编码

    通过查看其他博客的内容,整理一篇关于二进制霍夫曼编码的笔记供大家参考和讨论,如果有错误,欢迎大家联系我批评指正. 一.二进制霍夫曼的原理 我们可以将二进制霍夫曼编码拆分理解: 二进制即 0.1: 二进 ...

  10. 贪心算法哈夫曼编码c语言,贪心算法详解:哈夫曼编码

    理解贪心算法 贪心算法是一种算法思想,并不是一个具体的算法,因此我们用两个例子来理解什么样的问题适合用贪心算法解决. 例一 现在有一个能装 100g 物品的背包,和一些可拆分的物品(见表格),怎么装才 ...

最新文章

  1. 简单总结一下.net获得虚拟目录几个基本操作
  2. myBaits SQL
  3. 利用rank函数实现自动排序
  4. 解决fatal: 不是一个 git 仓库(或者任何父目录)的方法
  5. unreal4怎么设置游戏模式_在Unreal4中如何连接自定义服务器
  6. 从BlackHat2013中我们收获了什么
  7. Elon Musk发起投票,超7成参与者认为狗狗币是地球未来货币
  8. Zstack协议栈中CC2530协调器掉电重启后重新加入之前网络的方法
  9. PyQt5+周立功 CAN上位机制作
  10. 英特尔推出SD卡巨细电脑 配Atom处理器
  11. protobuf入门教程(四):repeated限定修饰符
  12. 14种异常检测方法汇总
  13. 抖音封禁3973个炫富账号,一股清流!
  14. 名帖41 伊秉绶 隶书《对联八幅》
  15. 不等号属于不等式吗_什么是不等式
  16. UPC-5594 Colorful Slimes(思维)
  17. 智测优聘梳理|工伤认定/工伤假的相关知识
  18. 骚年都2020年了你还在用EventBus吗?jetpack之liveData
  19. 用Linux的crontab命令来调度脚本作业
  20. GIF动态图录制工具

热门文章

  1. Appium Python API中文文档
  2. 微信小程序 自助停车,输入车牌号功能实现
  3. 【蓝桥杯省赛真题10】Scratch考试成绩 少儿编程scratch蓝桥杯省赛真题讲解
  4. python生成高斯(gauss)数据并保存为txt文件
  5. 思考1:为什么大多数人喜欢做重复性工作,而不是思考用更简单的方法或者思考按自己的思路解决问题。
  6. 期货反向跟单--管理的维度问题
  7. 【 五子棋对战平台(java_gobang) 】
  8. webpack学习之2.自动编译、实时重载LiveReload、热替换HMR
  9. 如何把设计稿中px值转化为想要的rem值
  10. 2001-2022年全国各城市气温数据(逐日、逐月、逐年)