【数据结构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中

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

相关推荐
玖玥拾10 小时前
C/C++ 数据结构(六)链表迭代器与底层
c语言·数据结构·c++·链表·stl库
牛油果子哥q10 小时前
AVL平衡树与红黑树深度精讲对比,平衡因子、四大旋转原理、着色规则、平衡策略、性能差异与面试手撕全解
数据结构·c++·面试
Irissgwe11 小时前
map/set/multimap/multiset 的底层逻辑与实现
数据结构·c++·算法·二叉树·stl·c·红黑树
IronMurphy11 小时前
【算法五十八】23. 合并 K 个升序链表
数据结构·算法·链表
noipp12 小时前
【无标题】
c语言·数据结构·c++·算法
郝学胜-神的一滴13 小时前
完全二叉树与堆底层原理深度剖析 | 手写C++大顶堆实现
java·开发语言·数据结构·c++·python·算法
悠仁さん14 小时前
数据结构 图(代码实现篇 C语言版)
数据结构·算法·图论
Shadow(⊙o⊙)16 小时前
专题四:前缀和
数据结构·算法
Irissgwe16 小时前
AVL树详解
数据结构·c++·算法·二叉树·c·二叉搜索树·avl
北域码匠16 小时前
奇偶归并排序:并行计算的排序利器
数据结构·算法·c#·排序算法