【数据结构15】哈夫曼树构建、编码(附手绘图解)

目录

一、基本知识

二、Huffman树编码实现

[2.1 Huffman树创建](#2.1 Huffman树创建)

[2.2 Huffman树的编码](#2.2 Huffman树的编码)

[2.3 代码实现Huffman树的创建](#2.3 代码实现Huffman树的创建)

[2.4 代码实现Huffman树的编码](#2.4 代码实现Huffman树的编码)


一、基本知识

路径:一个结点到另一个结点的通路被称为路径;如A结点到F结点之间的通路

路径长度:根到子节点每走一条边,长度 + 1,根节点路径长度为 0;又在一棵树中,规定根结点所在层数为1,那从根结点到第i层结点的路径长度为i-1,F结点的路径长度为3

节点的带权路径长度:(给每一个节点赋予一个新的数值,被称为这个结点的权),根到节点的路径长度 × 节点权重为该节点的带权路径长度;如F结点的带权路径长度为3*5

树的带权路径长度(WPL):为树中所有叶子结点的带权路径长度之和;如上图WPL = 5 * 3 + 2 * 4

等长编码:如ABCD分别用011 010 101 111表示,都是三个bit,是等长编码

变长编码:如在(AABCAADBBCD)A:1表示 B:01表示 C:001表示 次数出现概率高的用较短的编码表示,可以节省空间

前缀码:如A:11 B:110 ,11是110的前缀,这种是不合法前缀码,合法前缀码需任意编码都不是其他编码前缀(如此才能无歧义解码)

哈夫曼树:哈夫曼编码是一种合法的前缀码,同时也是最优变长编码------它不会出现前缀码冲突(不合法),且树的带权路径长度(WPL)最小 (哈夫曼编码一定是合法前缀码)

二、Huffman树编码实现

2.1 Huffman树创建

例:节点A-H、weight\[\] = {5,29,7,8,14,23,3,11,8}

2.2 Huffman树的编码

2.3 代码实现Huffman树的创建

复制代码
C

static void selectNode(HuffmanTree tree,int n,int *s1,int *s2)
{
    int mini = 0;
    // 找到第一个父节点为0的编号
    for (int i = 1;i <= n;++i)
    {
        if (tree[i].parent == 0)
        {
            mini = i;
            break;
        }
    }
    for (int i = 1;i<=n;++i)
    {
        if (tree[i].parent == 0)
        {
            if (tree[i].weight < tree[mini].weight)
            {
                mini = i;
            }
        }
    }
    *s1 = mini;
    // 开始找第二个最小权值的点
    for (int i=1;i<=n;++i)
    {
        if (tree[i].parent == 0 && i != *s1)
        {
            mini = i;
            break;
        }
    }
    for (int i = 1;i<=n;++i)
    {
        if (tree[i].parent == 0 && i != *s1)
        {
            if (tree[i].weight < tree[mini].weight)
            {
                mini = i;
            }
        }
    }
    *s2 = mini;
}
HuffmanTree createHuffmanTree(const int* w, int n)
{
    int m = 2*n -1;
    // 1.1 申请2n个单元,从1号索引开始存储数据
    HuffmanTree tree = malloc(sizeof(HuffmanNode) * (m+1));
    if (tree == NULL)
    {
        return NULL;
    }
    // 初始化1~2n-1个节点
    for (int i = 1;i<=m;++i)
    {
        tree[i].parent = tree[i].lChild = tree[i].rChild = 0;
        tree[i].weight = 0;
    }
    // 1.2设置初始化权值
    for (int i = 1;i<=n;++i)
    {
        tree[i].weight = w[i-1];
    }
    int s1,s2;
    // 填充n+1下标到m下标的空间
    for (int i = n+1;i<=m;++i)
    {
        // 在[1...i-1]范围内,父节点为0,权值最小的两个点
        selectNode(tree,i-1,&s1,&s2);
        // 将这2个权值最小的节点,组合到第i个位置上(父节点)
        tree[s1].parent = tree[s2].parent = i;
        tree[i].lChild = s1;
        tree[i].rChild = s2;
        tree[i].weight = tree[s1].weight + tree[s2].weight;
    }
    return tree;
}

2.4 代码实现Huffman树的编码

复制代码
C

HuffmanCode* createHuffmanCode(HuffmanTree tree, int n)
{
    // 生成n个字符的编码表,每个表项里保存编码的空间首地址
    HuffmanCode *codes = malloc(sizeof(HuffmanCode) * n);
    if (codes == NULL)
    {
        return NULL;
    }
    memset(codes,0,sizeof(HuffmanCode) * n);
    // 每求一个字符时,倒序构建,n个节点,树的高度最高是n,编码个数最多为n
    char *temp = malloc(sizeof(char) * n);
    int start;
    int p;      // 记录第i个位置的父节点
    int pos;    // 记录当前位置i
    for (int i = 1;i <= n;++i)
    {
        start = n-1;          // temp、start组合使用,从后往前
        temp[start] = '\0';   // n-1位置放'\0'
        pos = i;
        p = tree[i].parent;
        while (p)         // 第i个位置的父节点存在
        {
            --start;
            // 该父节点左孩子是pos(i),则'0',否则是右孩子'1'
            temp[start] = tree[p].lChild == pos ? '0':'1';
            pos = p;
            p = tree[p].parent;
        }
        // huffman树节点1-n,codes数组下标0-n-1
        codes[i-1] = malloc(sizeof(char) * (n-start));
        strcpy(codes[i-1],&temp[start]);  // 将temp中存的编码复制,至codes[i-1]位置
    }
    free(temp);
    return codes;
}

编码过程:

两数组:**codes:用来存编码 、temp:是临时数组,与start变量从数组尾到头编码

两变量: pos:存当前位置 、 p:存当前位置的父节点

每经历一个while循环,就将temp临时数组中存的内容复制到codes中

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!

相关推荐
m0_547486666 天前
《数据结构教程》全套 PPT课件2026
数据结构
tryxr6 天前
矩阵的几种基础变换
java·数据结构·算法·矩阵
mmmmath_36 天前
LeetCode.028.找出字符串中第一个匹配项的
数据结构·算法·leetcode
All for pursuit.6 天前
【栈-4】739.每日温度
数据结构·c++·算法·leetcode
All for pursuit.6 天前
【栈-5】84.柱状图中最大的矩形
数据结构·c++·算法·leetcode
渡我白衣6 天前
HttpRequest与HttpResponse的实现
服务器·数据结构·c++·人工智能·tcp/ip·机器学习·caffe
晴天的雨.9926 天前
【C++算法】和为s的两个数
开发语言·数据结构·c++·算法
淡海水6 天前
13-04-面试-源码级深度追问链
数据结构·unity·面试·c#·游戏引擎·源码·il2cpp
Logic1016 天前
C语言/数据结构位运算题解:异或XOR找出时尚聚会中的“独特颜色“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
2401_839080546 天前
C++常见八股
数据结构·c++·算法