Huffman 编码的编程与实现 C语言

Huffman 编码的编程与实现 C语言利用动态分配数组存储赫夫曼树 设计一组输入数据 假定为一组整数 能够对其进行如下操作 1 创建一个新的顺序表 实现动态空间分配的初始化 2 对输入的数据构造成一棵 Huffman 树 3 根据生成的 Huffman 树进行 Huffman 编码 4 实现对输入数据的 Huffman 编码输出 四 要求 1 实现 Huffman 树的生成 2 完成 Huffman 编码的输出 五 步骤

#include 
  
    #include 
   
     #include 
    
      #include 
     
       using namespace std; typedef char ElemType; typedef struct { ElemType elem; unsigned int weight; unsigned int parent, lchild, rchild, tag; }HTNode, * HuffmanTree; typedef char HuffmanCode; typedef int Status; typedef struct weight { char elem; unsigned int m_weight; }Weight; void Select(HuffmanTree HT, int n, int& s1, int& s2) { int i; s1 = s2 = 0; for (i = 1; i <= n; i++) { if (HT[i].weight < HT[s2].weight && HT[i].parent == 0 && s2 != 0) { if (HT[i].weight < HT[s1].weight) { s2 = s1; s1 = i; } else s2 = i; } if ((s1 == 0 || s2 == 0) && HT[i].parent == 0) { if (s1 == 0) s1 = i; else if (s2 == 0) { if (HT[i].weight < HT[s1].weight) { s2 = s1; s1 = i; } else s2 = i; } } } if (s1 > s2) { i = s1; s1 = s2; s2 = i; } } void HuffmanCoding(HuffmanTree& HT, HuffmanCode& HC, Weight*& w, int n) { // w存放n个字符的权值(均>0),构造哈夫曼树HT, // 并求出n个字符的哈夫曼编码HC //本函数实现选择方式:从左往右选择两个小权值结点,结点信息在前面的为左子树,其后为右子树 int i, j, m, s1, s2; char* cd; int p; int cdlen; if (n <= 1) return; m = 2 * n - 1; HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode)); // 0号单元未用 for (i = 1; i <= n; i++) { //初始化 HT[i].elem = w[i - 1].elem; HT[i].weight = w[i - 1].m_weight; HT[i].parent = 0; HT[i].lchild = 0; HT[i].rchild = 0; } for (i = n + 1; i <= m; i++) { //初始化 HT[i].weight = 0; HT[i].parent = 0; HT[i].lchild = 0; HT[i].rchild = 0; } printf("\n哈夫曼树的构造过程如下所示:\n"); printf("HT初态:\n 结点 weight parent lchild rchild"); for (i=1; i<=m; i++) printf("\n%4d%8d%8d%8d%8d",i,HT[i].weight, HT[i].parent,HT[i].lchild, HT[i].rchild); getchar(); for (i = n + 1; i <= m; i++) { // 建哈夫曼树 // 在HT[1..i-1]中选择parent为0且weight最小的两个结点, // 其序号分别为s1和s2。 Select(HT, i - 1, s1, s2); HT[s1].parent = i; HT[s2].parent = i; HT[i].lchild = s1; HT[i].rchild = s2; HT[i].weight = HT[s1].weight + HT[s2].weight; printf("\nselect: s1=%d s2=%d\n", s1, s2); printf(" 结点 weight parent lchild rchild"); for (j=1; j<=i; j++) printf("\n%4d%8d%8d%8d%8d",j,HT[j].weight, HT[j].parent,HT[j].lchild, HT[j].rchild); getchar(); } //------无栈非递归遍历哈夫曼树,求哈夫曼编码 HC = (HuffmanCode)malloc((n + 1) * sizeof(char*)); cd = (char*)malloc((n + 1) * sizeof(char)); // 分配求编码的工作空间 p = m; cdlen = 0; for (i = 1; i <= m; ++i) // 遍历哈夫曼树时用作结点状态标志 HT[i].tag = 0; while (p) { if (HT[p].tag == 0) { // 向左 HT[p].tag = 1; if (HT[p].lchild != 0) { p = HT[p].lchild; cd[cdlen++] = '0'; } else if (HT[p].rchild == 0) { HC[p] = (char*)malloc((cdlen + 1) * sizeof(char)); cd[cdlen] = '\0'; strcpy(HC[p], cd); } } else if (HT[p].tag == 1) { // 向右 HT[p].tag = 2; if (HT[p].rchild != 0) { p = HT[p].rchild; cd[cdlen++] = '1'; } } else { // HT[p].weight==2,退回退到父结点,编码长度减1 HT[p].tag = 0; p = HT[p].parent; --cdlen; } } } void OutputHuffmanCode(HuffmanTree HT, HuffmanCode HC, int n) { int i; printf("\nnumber---element---weight---huffman code\n"); for (i = 1; i <= n; i++) printf(" %d %c %d %s\n", i, HT[i].elem, HT[i].weight, HC[i]); } int main() { HuffmanTree HT; HuffmanCode HC; Weight* w; char c; // the symbolizes; int i, n; // the number of elements; int wei; // the weight of a element; printf("请输入准备构建哈夫曼树的结点数:"); cin >> n; //cout< 
       
      
     
    
  

2.程序结果:

1)程序运行,我使用的测试数据如下所示:

Huffman 编码的编程与实现 C语言

2)首先按照要求完成了哈夫曼树的构建:

Huffman 编码的编程与实现 C语言

Huffman 编码的编程与实现 C语言

3)最终完成哈夫曼编码,结果与预期一致。

Huffman 编码的编程与实现 C语言

六 、小结:

       此次是关于哈夫曼树的编程与实现,通常给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。

        我先输入了权值的 n 个结点,并且在构建哈夫曼树时我采用了如下办法:首先在 n 个权值中选出两个最小的权值,对应的两个结点组成一个新的二叉树,且新二叉树的根结点的权值为左右孩子权值的和;在原有的 n 个权值中删除那两个最小的权值,同时将新的权值加入到 n–2 个权值的行列中,以此类推;重复上述过程,直到所以的结点构建成了一棵二叉树为止,就得到了哈夫曼树。通常查找权重值最小的两个结点的思想是:从树组起始位置开始,首先找到两个无父结点的结点(说明还未使用其构建成树),然后和后续无父结点的结点依次做比较,有两种情况需要考虑:如果比两个结点中较小的那个还小,就保留这个结点,删除原来较大的结点;如果介于两个结点权重值之间,替换原来较大的结点。最终实现了描述的功能。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/199200.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月26日 下午1:37
下一篇 2026年3月26日 下午1:37


相关推荐

  • 解决ubuntu16.04中codeblocks中文显示不全的问题[通俗易懂]

    解决ubuntu16.04中codeblocks中文显示不全的问题[通俗易懂]ubuntu16.04中安装中文库、中文输入法、搜狗输入法、解决终端无法显示中文的问题、安装字体(YaheiConsolas字体)、更换漂亮绚丽flatbulous主题。codeblock设置字体为:kacstdigital或centuryschoolbookl解决中文注释显示不全的问题,修改codeblocks丑陋的运行窗口为ubuntu16.04默认的终端。

    2022年7月26日
    20
  • 引用传递和值传递以及链表中的LinkList L、LinkList *L、LinkList &L

    引用传递和值传递以及链表中的LinkList L、LinkList *L、LinkList &L函数参数传递的两种方式为值传递和引用传递 1 传值方式传参 c 语言是按值传递的 在函数中被传递的参数的本身 实参 是不能被修改的 参数 x 传进去的时候会被复制了一份 copy 此后的修改都是在临时变量 copy 上 出了函数体 copy 被销毁 x 还是原来的 x 根本就没有被修改过 所以对变量 x 的修改无效 如果想要修改传入的参数 有两种方法 传地址 传入 x 的地址 也就是将指向 x 的指针作为参数进行传

    2026年3月19日
    2
  • java程序员面试宝典第四版pdf下载

    java程序员面试宝典第四版pdf下载引言最近项目上线的频率颇高 连着几天加班熬夜 身体有点吃不消精神也有些萎靡 无奈业务方催的紧 工期就在眼前只能硬着头皮上了 脑子浑浑噩噩的时候 写的就不能叫代码 可以直接叫做 Bug 我就熬夜写了一个 bug 被骂惨了 阿里面试总结 1 一面首先确认对阿里的意向度 其次面试官会针对你曾经做过的项目来做具体技术的交流 你对项目细节是不是掌握到位 以及 java 技术基础和原理掌握程序 比如并发编程以及数据库和 JVM 三个方面 也会交流到分布式 线程池的实现等等 重点考察有没有深入钻研技术和技术上的亮点 2 二

    2026年3月16日
    3
  • 数仓(三):分层设计 ODS-DWD-DWS-ADS

    数仓(三):分层设计 ODS-DWD-DWS-ADS一、数仓建模的意义,为什么要对数据仓库分层?只有数据模型将数据有序的组织和存储起来之后,大数据才能得到高性能、低成本、高效率、高质量的使用。1、清晰数据结构:每一个数据分层都有它的作用域,这样我们在使用表的时候能更方便地定位和理解。数据关系条理化:源系统间存在复杂的数据关系,比如客户信息同时存在于核心系统、信贷系统、理财系统、资金系统,取数时该如何决策呢?数据仓库会对相同主题的数据进行统一建模,把复杂的数据关系梳理成条理清晰的数据模型,使用时就可避免上述问题了。2、数据血缘追…

    2022年6月26日
    33
  • Ubuntu18.04安装Ros(最新最详细亲测)「建议收藏」

    Ubuntu18.04安装Ros(最新最详细亲测)「建议收藏」跟我一步一步来,带你轻松安装ROS

    2022年6月15日
    218
  • 3 InetAddress

    3 InetAddressInetAddress的使用

    2022年6月23日
    26

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号