数据结构学习记录DAY13 :哈夫曼树(上)

哈(赫)夫曼树和哈(赫)夫曼编码

  • 路径 一个结点到另外一个结点的通路,称为路径 (祖先结点到子孙结点)
  • 路径长度: 每经过一个结点,路径长度就增加1,不包括起始结点的
  • 结点权值:对于结点赋予一个数值,表示结点的权值 比较:结点元素出现的次数
  • 带权路径长度: 从根点出发到该结点的路径长度 乘以 该结点的权值
  • 树的带权路径长度 (WPL): 树中所有叶子结点的带权路径长度之和
  • 哈夫曼树:最优二叉树,由n个叶结点组成的二叉树的带权路径长度最短
    • 结点相同,构成的哈夫曼树可能不唯一,但树的带权路径长度相等
    • 把n个结点构成哈夫曼树,这n个结点必然作为叶子结点,需要添加n-1个分支结点
构建哈夫曼树
  • 遵循的原则:权重越大离根结点越近
  • 算法描述过程
      1. 把n个叶结点看作n棵独立的树,构成森林F
      1. 创建一个新的结点,然后从森林F中选取两棵根结点权值最小的树作为新结点的左右子树,并且把新的结点的权值设置为这两棵树根结点权值之和
      1. 从森林F中把刚才选取两棵树删除,并且把新的结点作为树的根结点加入到森林中
      1. 重复2和3的步骤,直到森林中只剩下一棵树为止
A:3   B:4     C:1    D:5    E:10     F:6    G:2E:10   F:6    D:5    B:4   A:3    G:2   C:13/   \
G     C
E:10   F:6    D:5    B:4  A:3    GC:36/  \
A    3/ \G   C
E:10   F:6   A GC:6  D:5    B:49/ \
D   BFx:12  E:10  DB:9  12/ \F   6/  \ A    3/ \G   C
哈夫曼树:31/  \19      12/  \    /  \E    9  F    6/ \     / \D   B   A   3/  \G    C
A:3   B:4     C:1    D:5    E:10     F:6    G:2
E:00   D:010  B:011  F:10   A:110  G:1110  C:11113x3 + 4x3 + 1x4 + 5x3 + 10x2 + 6x2 + 2x4
= 9 + 12 + 4 + 15 + 20 + 12 + 8

哈夫曼树特性

  1. 每个初始结点最终都成为叶结点,且权值越小的结点到根结点的路径长度越大
  2. 哈夫曼树的结点总数为2n − 1
  3. 哈夫曼树中不存在度为1的结点
  4. 哈夫曼树并不唯一,但WPL必然相同且为最优
哈夫曼编码
  • 编码

    • 定义编码
    • ASCII 定长编码 每个字符都是8个二进制位
      • A 65 0100 0001
      • B 66 0100 0010
      • C 67 0100 0011
      • D 68 0100 0100
    • unicode 万国码 4byte
    • 变长编码 utt-8 中文汉字2-4byte gbk 2byte
    • 哈夫曼编码就是变长编码
    • 哈夫曼编码是前缀编码 任意一个字符的编码都不会是另外一个字符编码的前缀
    • 前缀编码不会有歧义 非前缀编码会产生歧义

100道选择题: 按照ascii发送: 传输100byte

A: 00 B: 01 C: 10 D: 11 100*2bit/8 byte = 25byte

A:50 B:20 C:15 D:15

A:0 B:10 C:110 D:111 50x1+20x2+30x3bit/8 = 180/8 = 22.5byte

A:0 B:00 C:010 D:011 非前缀编码

  • 由哈夫曼树获取哈夫曼编码

    • 从根结点出发,左子树为0,右子树为1,到所有叶子结点所经过的路径就构成了哈夫曼编码

      有了以上的知识点就可以准备着手创建哈夫曼树和生成哈夫曼编码了
      多文件编程如下:
      main.c

      #include "Huffman.h"
      void printEWC(unsigned char elem, size_t weight, char *code)
      {printf("%c   %u    %s\n",elem, weight, code);
      }int main()
      {unsigned char elm[] = "ABCDEFGHIJ";size_t weight[] = {5,7,4,3,1,2,6,9,0,8};HUFF tree = create_HuffmanTree(elm, weight, 10);get_HuffCode(tree);foreach_HuffmanTree(tree, printEWC);destroy_HuffmanTree(tree);
      }

Huffman.h

 #ifndef _HUFFMAN_H_
#define _HUFFMAN_H_#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>#define SUCCESS 0
#define FAILURE -1
#define CODE_LEN 256typedef unsigned char ElemType;struct HuffTree{ElemType data;//size_t weight;//权重char code[CODE_LEN];//存储时转化为而精致struct HuffTree *lchild;struct HuffTree *rchild;
};typedef struct HuffTree *HUFF;HUFF create_HuffmanTree(ElemType elems[], size_t weight[], size_t n);//elems为元素, weight为权重
//获得哈夫曼编码
void get_HuffCode(HUFF tree);
//输出哈夫曼编码
void foreach_HuffmanTree(HUFF tree, void (*visit)(ElemType, size_t, char*));
//
void destroy_HuffmanTree(HUFF tree);#endif// _HUFFMAN_H_

Huffman.c

#include "Huffman.h"int compareWeight(const void *v1, const void *v2)
{HUFF *h1 = (HUFF*) v1;HUFF *h2 = (HUFF*) v2;//return ((*h2)->weight - (*h1)->weight);if((*h1)->weight < (*h2)->weight){return 1;}else if((*h2)->weight < (*h1)->weight){return -1;}else{return 0;}
}//elems为元素, weight为权重
HUFF create_HuffmanTree(ElemType elems[], size_t weight[], size_t n)
{//HUFF *tree = (HUFF*)malloc(sizeof(HUFF*) * n);HUFF tree[n];if(NULL == tree){return NULL;}for(int i = 0; i < n; ++i){tree[i] = (HUFF)malloc(sizeof(struct HuffTree));tree[i]->data = elems[i];tree[i]->weight = weight[i];tree[i]->lchild = tree[i]->rchild = NULL;memset(tree[i]->code, 0, CODE_LEN);}qsort(tree, n, sizeof(HUFF), compareWeight);for(int i = 0; i < n; ++i){//此时i为最后一个结点printf("%c(%u)", tree[i]->data,tree[i]->weight);}printf("\n");HUFF root = NULL;for(int i = n-1; i > 0; i--){root = (HUFF)malloc(sizeof(struct HuffTree));root->lchild = tree[i-1];root->rchild = tree[i];root->weight = tree[i-1]->weight + tree[i]->weight;//memset(root->code, 0, CODE_LEN);int j;for(j = i - 2; j >= 0 && tree[j]->weight < root->weight; --j){tree[j+1] = tree[j];}tree[j + 1] = root;}root = tree[0];return root;}
//获得哈夫曼编码
void get_HuffCode(HUFF tree)
{if(NULL != tree){if(tree->lchild != NULL){strcpy(tree->lchild->code,tree->code);strcat(tree->lchild->code, "0");get_HuffCode(tree->lchild);}if(tree->rchild != NULL){strcpy(tree->rchild->code,tree->code);strcat(tree->rchild->code, "1");get_HuffCode(tree->rchild);}}
}
//输出哈夫曼编码
void foreach_HuffmanTree(HUFF tree, void (*visit)(ElemType, size_t, char*))
{if(tree != NULL){if(tree->lchild == NULL && NULL == tree->rchild){visit(tree->data, tree->weight, tree->code);}else{foreach_HuffmanTree(tree->lchild, visit);foreach_HuffmanTree(tree->rchild, visit);}}
}
//
void destroy_HuffmanTree(HUFF tree)
{if(tree != NULL){destroy_HuffmanTree(tree->lchild);destroy_HuffmanTree(tree->rchild);free(tree);}
}

文件的压缩和解压

  • 利用哈夫曼编码对文件进行压缩和解压
  • 算法过程
    • 读取文件中的内容,统计每一个字符出现的次数
    • 根据得到的字符-对应的次数构建哈夫曼树,得到哈夫曼编码
    • 对文件中的字符用哈夫曼编码进行压缩
    • 为了能够解压,需要把哈夫曼树存储的到文件中

以上
希望有帮到你

数据结构学习——哈夫曼树相关推荐

  1. 数据结构与算法学习④(哈夫曼树 图 分治回溯和递归)

    数据结构与算法学习④(哈夫曼树 图 回溯和递归 数据结构与算法学习④ 1.哈夫曼树 1.1.相关概念 1.2.哈夫曼树的构建 1.3.哈夫曼编码 1.4.面试题 2.图 2.1.图的相关概念 2.2. ...

  2. 数据结构“基于哈夫曼树的数据压缩算法”的实验报告

    一个不知名大学生,江湖人称菜狗 original author: jacky Li Email : 3435673055@qq.com Last edited: 2022.11.20 目录 数据结构& ...

  3. 数据结构(哈夫曼树+KMP)之 数据加密+解密

    数据结构(哈夫曼树+KMP)之 数据加密+解密 原理:参考趣学数据结构 代码: #include<stdio.h> #include<stdlib.h> #define N 1 ...

  4. 2020-10-1 //严蔚敏《数据结构》 //赫夫曼树及其应用:创建顺序赫夫曼树创建及得到赫夫曼编码

    //严蔚敏<数据结构> //赫夫曼树及其应用:创建顺序赫夫曼树创建及得到赫夫曼编码 //(从叶子结点到根逆向求每个字符的赫夫曼编码)以及(无栈非递归遍历赫夫曼树,求赫夫曼编码) //自学中 ...

  5. 数据结构之哈夫曼树的基本知识

    前面讲到了线索二叉树的基础知识后,今天我们紧随其后来说说另一种特殊二叉树---哈夫曼树.这几种特殊二叉树可能理解起来有点难度,没关系,我只能说慢慢理解,隔一段时间拿出来理解理解,说不定自己随着学的东西 ...

  6. 数据结构 基于哈夫曼树的数据压缩算法

    数据结构 基于哈夫曼树的数据压缩算法 实验目的 实验内容 实验提示 实验代码 实验小结 实验目的 1.掌握哈夫曼树的构造算法. 2.掌握哈夫曼编码的构造算法. 实验内容 问题描述 输入一串字符串,根据 ...

  7. 算法学习笔记——数据结构:哈夫曼树、带权路径长度WPL、哈夫曼编码

    引入 合并果子问题如下: 有n堆果子,每次可以合并任意两堆果子,耗费体力值为[两堆果子数之和],最终在n-1次合并后,得到一堆果子. 给出合并的方案,使得耗费的体力值最小 例如有3堆果子,质量依次为1 ...

  8. 【数据结构】哈夫曼树与哈夫曼编码

    定义 带权路径长度(WPL):设二叉树有n个叶子结点,每个叶子结点带有权值wkw_kwk​,从根节点到每个叶子结点的长度为lkl_klk​,则每个叶子结点的带权路径长度之和就是:WPLWPLWPL=∑ ...

  9. 【数据结构】赫夫曼树

    数据结构赫夫曼树 /*名称:赫夫曼树语言:数据结构C语言版 编译环境:VC++ 6.0日期: 2014-3-26 */#include <stdio.h> #include <lim ...

最新文章

  1. 从源码分析DEARGUI之add_tooltip
  2. 可溶于水的机器人见过吗?明胶和糖3D打印而成,现登Science子刊封面
  3. Jenkins 使用 Kubernetes Plugin 完成持续构建与发布
  4. keras 导出onnx并使用
  5. eclipse下使用maven配置库托管jar包
  6. 对称矩阵(Symmetric Matrices)
  7. 数据挖掘系列(4)使用weka做关联规则挖掘
  8. Jquery 获取select,radio 和 checkbox的值
  9. Active Record 数据验证
  10. java与bartender_Java调取Bartender使用教程.md
  11. mysql优化之query优化
  12. python查看是否存在某个变量名
  13. SharePoint 2010学习资源
  14. CSS3 过渡 transition
  15. dnsmasq-2.48没有ipset特性,安装dnsmasq-2.71来支持ipset
  16. Unity应用架构设计(4)——设计可复用的SubView和SubViewModel(Part 2)
  17. 人工智能算法自动化测试_自动化:算法如何塑造我和你的生活
  18. 常用视频像素格式NV12、NV21、I420、YV12、YUYV
  19. 百度网盘有linux版本的,百度网盘Linux版发布,网友反馈“限速该有还是有”
  20. MP4提取音频文件,并且转换为16KHz采样率 16 bit

热门文章

  1. keil中添加stc单片机芯片包的方法
  2. QQ炫舞官网选项卡效果
  3. While()和scanf的搭配使用问题
  4. geohash 总结
  5. openCV中的saturate_cast()方法
  6. 计算机内存储器和外存储器相比较,计算机的内存储器与外存储器相比较
  7. 6个很少有人知道图片素材网站,将你的需求一网打尽
  8. 删除数组(对象)中的某一项
  9. php jcrop(),php jquery jcrop和imagejpeg
  10. nz-zorro的icon图标如何进行大小和样式调整