文章目录

  • 赫夫曼树
    • 1. 赫夫曼树介绍:
    • 2. 赫夫曼树的创建过程:
    • 3. 赫夫曼树的性质:
    • 4. 赫夫曼编码:
    • 5. 赫夫曼树与赫夫曼编码的c语言代码实现:

赫夫曼树

1. 赫夫曼树介绍:

​ 赫夫曼树是一种带权重的树,它的结点中有一项数据是权重信息,根据结点中的权重生成一棵二叉树,结点的权生越大,离根结点就越近。

2. 赫夫曼树的创建过程:

​ 1、获取值和权重信息、。

​ 2、根据值和权重信息生成若干棵度为0的树,存储到小根堆中形成森林。

​ 3、从小根堆获取到两棵权重最轻的树,把这两棵树的权重相加生成一个新的只有权重的空白树,它的左子树指向权重较小的树,右子树指向权较大的树,然后再把新的树添加到小根堆。

​ 4、重复步骤3,直到小根堆中只有一棵树,它就是创建出的赫夫曼树的根结点。

3. 赫夫曼树的性质:

​ 1、赫夫曼树只有前序遍历才有意义。

​ 2、赫夫曼树的非叶子结点都是只有权重信息,而没有值的空白结点,反之,所有叶子结点都是既有权重又有值的结点。

​ 3、结点的权重越大,结点的高度编号就是越小,离根结点就越近,前遍历访问的速度就越快,反之结点的权重越小,结点的高度编号就越大,离根结点就是越远,前序遍历访问的速度就越慢。

4. 赫夫曼编码:

​ 从赫夫曼树的根结点出发进行前序遍历,遍历过程中把往左子树遍历记作0,把往右子树遍历记作1,到达叶子结点时,走过的路径所形成的01信息被称为赫夫曼编码,使用这种编码就访问到赫夫曼树根结点出发访问到叶子结点中的数据。

​ 这种编码的特点就是权重越大的数据,生成的编码就越短,权重越小的数据,生成的编码就越长。

​ 这种编码可以用于提高数据传输效率,还有文件的压缩和解压。

5. 赫夫曼树与赫夫曼编码的c语言代码实现:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>
#include <unistd.h>
#include <math.h>
#include "heap.h"typedef struct CharCode
{uint32_t code; // 赫夫曼编码uint8_t cnt;   // 编码位数
} CharCode;// 赫夫曼编码数组
CharCode code_arr[128];// 赫夫曼树结点
typedef struct TreeNode
{uint8_t data;   // 数据uint32_t weight; // 权重struct TreeNode *left;struct TreeNode *right;
} TreeNode;// 用于比较结点权重的回调函数,给小堆根使用的
int node_cmp(const void *p1, const void *p2)
{if (((TreeNode *)p1)->weight > ((TreeNode *)p2)->weight)return 1;if (((TreeNode *)p1)->weight < ((TreeNode *)p2)->weight)return -1;return 0;
}TreeNode *create_node(char data, size_t weight)
{TreeNode *node = malloc(sizeof(TreeNode));node->data = data;node->weight = weight;node->left = NULL;node->right = NULL;return node;
}void _create_code(TreeNode *root, uint8_t path, uint32_t code, uint8_t cnt)
{if (NULL == root)return;code = (code << 1) + path;// 到达叶子结点时,记录赫夫曼编码if (0 != root->data){code_arr[root->data].code = code;code_arr[root->data].cnt = cnt;return;}_create_code(root->left, 0, code, cnt + 1);_create_code(root->right, 1, code, cnt + 1);
}// 生成赫夫曼编码
void create_code(TreeNode *root)
{_create_code(root->left, 0, 0, 1);_create_code(root->right, 1, 0, 1);
}// 生成赫夫曼树
TreeNode *init_tree(char *val_arr, size_t *weight_arr, size_t len)
{// 创建存储森林的小根堆Heap *heap = create_heap(len, node_cmp);for (int i = 0; i < len; i++){push_heap(heap, create_node(val_arr[i], weight_arr[i]));}// 直到堆中只有一个结点,这就是赫夫曼树的根结点while (1 < size_heap(heap)){// 从堆中获取一个权重最小的树,当作左子树TreeNode *left = top_heap(heap);pop_heap(heap);// 从堆中获取一个权重最小的树,当作右子树TreeNode *right = top_heap(heap);pop_heap(heap);// 左右子树的权重相加生成一个新的空白结点TreeNode *root = create_node(0, left->weight + right->weight);root->left = left;root->right = right;// 新的结点加入小根堆push_heap(heap, root);}TreeNode *root = top_heap(heap);destroy_heap(heap);return root;
}// 压缩文件
int compress_file(const char *oldfile, const char *newfile)
{FILE *rfp = fopen(oldfile, "r");if (NULL == rfp){printf("%s文件打开失败!\n", oldfile);return -1;}FILE *wfp = fopen(newfile, "w");if (NULL == wfp){printf("压缩文件失败!\n");return -1;}fseek(rfp, 0, SEEK_END);fprintf(wfp, "%ld\n", ftell(rfp));rewind(rfp);uint8_t buf[4096], cnt = 0;uint32_t data = 0, offset = 0xffffffff;int ret;while (ret = fread(buf, 1, sizeof(buf), rfp)){for (int i = 0; i < ret; i++){if (32 > cnt + code_arr[buf[i]].cnt){data = (data << code_arr[buf[i]].cnt) + code_arr[buf[i]].code;cnt += code_arr[buf[i]].cnt;}else{// 32-cnt 计算出data中还余多少位data = (data << (32 - cnt)) + (code_arr[buf[i]].code >> (code_arr[buf[i]].cnt - (32 - cnt)));fwrite(&data, 1, sizeof(data), wfp);data = (~(offset << (code_arr[buf[i]].cnt - (32 - cnt)))) & code_arr[buf[i]].code;cnt = code_arr[buf[i]].cnt - (32 - cnt);}}}data = data << (32 - cnt);fwrite(&data, 1, sizeof(data), wfp);fclose(rfp);fclose(wfp);return 0;
}int dp_file(TreeNode *root, const char *filename, const char *oldfile)
{FILE *rfp = fopen(filename, "r");if (NULL == rfp){printf("解压失败!\n");return -1;}long filesize;fscanf(rfp, "%ld\n", &filesize);FILE *wfp = fopen(oldfile, "w");if (NULL == wfp){printf("解压失败!\n");return -1;}unsigned int data;TreeNode *node = root;while (fread(&data, 1, sizeof(data), rfp)){for (int i = 0; i < 32; i++){if ((data << i) & 0x80000000)node = node->right;elsenode = node->left;if (0 != node->data){fwrite(&node->data, 1, 1, wfp);node = root;}}}fclose(rfp);fclose(wfp);return truncate(oldfile, filesize);
}int main(int argc, const char *argv[])
{char val_arr[] = {9, 10, 12, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126};size_t weight_arr[] = {16468, 29797, 15, 173045, 243, 916, 8025, 11, 24, 571, 1177, 8000, 8016, 16626, 517, 7384, 1855, 8775, 13269, 5276, 4848, 3603, 2032, 2593, 886, 3292, 805, 1219, 1360, 563, 4162, 943, 1248, 1032, 104, 241, 8184, 2145, 6653, 4971, 12331, 3990, 4196, 4170, 9197, 92, 856, 8929, 5168, 8000, 8562, 7509, 116, 11576, 10356, 12187, 4616, 1346, 2660, 3251, 1510, 859, 213, 808, 195, 16, 48314, 739, 35359, 8675, 21905, 27939, 79328, 25790, 8803, 17961, 48009, 361, 2336, 22424, 11352, 47506, 34893, 13171, 470, 40014, 35301, 57634, 16370, 4914, 6093, 4605, 6933, 2144, 440, 577, 435, 11};// 数据+权重构建出森林存储到小根堆里面TreeNode *root = init_tree(val_arr, weight_arr, sizeof(val_arr));create_code(root);printf("%d\n", compress_file("/usr/include/elf.h", "test.dat"));printf("%d\n", dp_file(root, "test.dat", "test.h"));return 0;
}

赫夫曼树介绍、赫夫曼树的性质、赫夫曼编码、赫夫曼树与赫夫曼编码的应用相关推荐

  1. 赫夫曼树建立c语言源程序编译结果详细解释,哈夫曼树的建立与实现最终版(备份存档)...

    <哈夫曼树的建立与实现.doc>由会员分享,可免费在线阅读全文,更多与<哈夫曼树的建立与实现(最终版)>相关文档资源请在帮帮文库(www.woc88.com)数亿文档库存里搜索 ...

  2. 图解 赫夫曼编码?(赫夫曼大叔开讲啦!!!)

    点击关注上方"五分钟学算法", 设为"置顶或星标",第一时间送达干货. 转自景禹 小禹禹,你知道赫夫曼树吗?不知道哎! 那景禹今天就给你细细道来,在介绍赫夫曼树 ...

  3. 哈夫曼java_哈夫曼树和哈夫曼编码介绍以及Java实现案例

    1.哈夫曼树 1.1哈夫曼树简介 哈夫曼树:给定N个权值作为N个叶子节点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree).哈夫曼树 ...

  4. 【数据结构和算法笔记】哈夫曼树的概念,构造和应用(利用哈夫曼编码压缩文本)

    目录 哈夫曼树定义: 构造哈夫曼树: 哈夫曼编码 前缀编码: 应用(压缩文本) 哈夫曼树定义: 构造哈夫曼树: 哈夫曼编码 前缀编码:  哈夫曼编码是前缀编码 哈夫曼树的性质 哈夫曼树的任意非叶结点的 ...

  5. java中哈夫曼编码所用的函数_数据结构(java语言描述)哈夫曼编码

    原理:哈夫曼编码是根据将已给出的权值作为叶子结点,生成一颗哈夫曼树,然后使得权重最小. 首先生成已给权重的所有的叶子结点,然后取所有节点中最小和次小的结点作为左右孩子生成一个哈夫曼树,计算出父节点的权 ...

  6. 清晰易懂的马尔科夫链原理介绍

    马尔科夫链是一种非常常见且相对简单的统计随机过程,从文本生成到金融建模,它们在许多不同领域都得到了应用.马尔科夫链在概念上非常直观且易于实现,因为它们不需要使用任何高级的数学概念,是一种概率建模和数据 ...

  7. 马尔科夫链原理介绍【通俗易懂】

    介绍 马尔科夫链是一种非常常见且相对简单的统计随机过程,从文本生成到金融建模,它们在许多不同领域都得到了应用.马尔科夫链在概念上非常直观且易于实现,因为它们不需要使用任何高级的数学概念,是一种概率建模 ...

  8. 何水无鱼,何山无石,何树无枝,何子无父,何女无夫,何城无市

    此谜语有6种解法:六种解法 解一: <释迦凡尘语录>记:南水无鱼?无山无石?阿人无父?弥女无夫?陀树无枝?佛城无市 ?隐喻<南无阿弥陀佛>六字.名曰<劝修经>. 解 ...

  9. python做马尔科夫模型预测法_Python实现HMM(隐马尔可夫模型)

    1. 前言 隐马尔科夫HMM模型是一类重要的机器学习方法,其主要用于序列数据的分析,广泛应用于语音识别.文本翻译.序列预测.中文分词等多个领域.虽然近年来,由于RNN等深度学习方法的发展,HMM模型逐 ...

最新文章

  1. 带动画效果的卷积神经网络的讲解.pptx
  2. python基础(part13)--包
  3. 泸西一中2021高考成绩查询,云南红河州四所好高中,红河州一中一本率领先,建水一中不容小觑...
  4. Halcon学习笔记:select_points_object_model_3d(3D对象模型阀值分割)
  5. e3 v3服务器芯片组,请问e3 1231 v3搭配下面哪款主板性价比最高?最适合?为什么?
  6. android支付宝余额怎么做,android实现类似于支付宝余额快速闪动的效果
  7. java 生成xml数据
  8. 评价法(四):yaahp软件——层次分析法模块使用
  9. 红外遥控Arduino智能小车
  10. 佐罗一键新机数据导出导入文件夹
  11. 事务Transaction的理解(一)
  12. 常用的网络进行广告推广的落实措施都有哪些渠道呢
  13. less css 视频教程
  14. 2018中科院计算所夏令营面试经历
  15. [计算机组成原理] 02 数据的表示和运算(2)
  16. 王道OS-磁盘存储器管理
  17. OC 技术 原生地图(源码)
  18. Mybatis-Plus条件构造器学习and方法
  19. 程序员未来的出路与如何转型
  20. ZIP RAR 压缩文件解密工具,亲测有效

热门文章

  1. 腾讯面试——SNG,QQ音乐
  2. android gphone 论坛,Android,任重道远,希望给想玩GPhone的同志们提个醒
  3. matlab数字不科学计算,利用MATLAB求解科学计算问题,完全不需要数值计算方法。...
  4. [转]文本相似度算法
  5. 计算机网络的广泛应用对媒体技术,计算机网络中多媒体技术的应用
  6. 十年老Python程序员:给我一个链接,没有我不能爬的视频,只有我顶不住的视频
  7. 5.1声道和7.1声道有什么区别 哪个好
  8. android s905 编译_NanoPi K2 (Amlogic S905) Ubuntu 16.04 编译Android 5.1系统源码
  9. 一品多码的成因和安仕达软件的解决办法
  10. Kolin之面向对象-1