c语言数据结构-哈夫曼树

 (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 

目录

哈夫曼树的定义 

构造哈夫曼树 

编码过程 


哈夫曼树的定义 

假设有 m个权值 {𝒘1 ,𝒘 2,  ··· , 𝒘 m } 可以构造一棵含n个叶子结点的二叉树,每个叶子结点的权为𝒘 𝒊 ,则其中带权路径长度 WPL最下的二叉树称作最优二叉树或哈夫曼树  

路径:a→b的路径:a→ 𝒘 2 、 𝒘 2 → 𝒘 𝟐 、 𝒘 1 → 𝒘 3 、 𝒘 𝟒 → 𝐛
路径长度:a→b的路径长度:4
树的路径长度:从树根到每一结点的路径长度之和 

:对实体的某个或某些属性的数值化描述

结点的带权路径长度为从该结点到树根之间的路径长度与结点上权的乘积

数的带权路径长度为树中所有叶子结点的带权路径长度之和

/** Huffman树结点 */
typedef struct haffNode {
    char data;                      //用来存放字符的数据域
    int weight;                     //权重
    struct haffNode* leftChild;    //左孩子
    struct haffNode* rightChild;   //右孩子
}HaffNode;
/**以顺序结构存储的树结点,依次构建编码解码的字符映射表 */
HaffNode node[MAX_SIZE];

构造哈夫曼树 

1.根据给定的n个权值{w 1 ,w 2 ,……w n },构造n棵只有根结点的二叉树。
2.在森林中选取两棵根结点权值最小的树作左右子树,构造一棵新的二叉树,置新二叉树根
   结点权值为其左右子树根结点权值之和。
3.在森林中删除这两棵树,同时将新得到的二叉树加入森林中。
重复上述两步,直到只含一棵树为止,这棵树即哈夫曼树。

/** 用来保存左子树结点 */
HaffNode left[HALF_MAX];

/** 用来保存右子树结点 */
HaffNode right[HALF_MAX];

/** 冒泡排序:以权值大小降序 */
void SortHaffman(HaffNode* node, int length) 
{
    HaffNode tempNode;
    for (int i = 0; i < length - 1; i++)
    {
        for (int j = 0; j < length - i - 1; j++)
        {
            //权值小的结点后移
            if (node[j].weight < node[j + 1].weight)
            {
                tempNode = node[j];
                node[j] = node[j + 1];
                node[j + 1] = tempNode;
            }
        }
    }
}

/**
 * 构造赫夫曼树
 *  node 赫夫曼树的结点数组
 *  length 结点数组的长度
 */
void CreateHaffman(HaffNode* node, int length)
{
    if (length <= 1)
        return;                 //数组长度为1时结束递归
    SortHaffman(node, length);              //将结点数组按weight(权)从大到小排列
    //构建一个以末尾两个结点为左右子结点的父节点,该父节点的权值为两个子结点权值之和
    HaffNode parent;
    //因为排过序了,所以最后一个结点[length-1]的权值肯定最小
    left[length] = node[length - 1];        //权值第二小的结点在左
    right[length] = node[length - 2];       //权值最小的结点在右
    parent.weight = left[length].weight + right[length].weight; //父节点权值为左右结点权值之和
    parent.leftChild = &left[length];       //左子树
    parent.rightChild = &right[length];     //右子树

    //将倒数第二位替换为该父节点,长度-1,递归创建赫夫曼树
    node[length - 2] = parent;
    CreateHaffman(node, length - 1);
}

编码过程 

分解接收的字符串:遇“0”向左,遇“1”向右;一旦到达叶子结点,则译出一个字符,反复由根触发,直到译码完成。

特点:每一码都不是另一码的前缀,绝对不会错译

/**
 * 编码过程(压缩过程)
 * @param node 结点数组
 * @param keepCode 返回存储编码后的字符数组
 * @param index 当前操作的字符数组下标
 */
void Coding(HaffNode* node, char* keepCode, int index) {
    if (!node) return;
    //处理叶结点
    if (node->leftChild == NULL || node->rightChild == NULL) {
        //给编码数组设置一个终止符,形成一个完整的字符串,方便拷贝(防止拷贝到之前的编码)
        keepCode[index] = '\0';
        //node->data-0是char型转int型的简便方法
        strcpy(code[node->data - 0], keepCode);
        return;
    }
    //左分支编码为'0', 右分支编码为'1'
    keepCode[index] = '0';
    Coding(node->leftChild, keepCode, index + 1);
    keepCode[index] = '1';
    Coding(node->rightChild, keepCode, index + 1);
}
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小周不摆烂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值