哈夫曼树(Huffman Tree) c语言实现

哈夫曼树

        哈夫曼树(Huffman Tree)是一种用于压缩数据的数据结构。哈夫曼树是一种二叉树,它的每个节点都有一个权重,表示该节点在编码中出现的频率。哈夫曼树的构建过程如下:

  1. 将所有节点按照权重从小到大排序。
  2. 选择权重最小的两个节点,将它们合并成一个新节点,新节点的权重等于这两个节点的权重之和。
  3. 将新节点加入排序后的节点列表中。
  4. 重复步骤2和3,直到只剩下一个节点

图解

代码实现

#include "LHuffTree.h"
#include "LSort.h"

#include <math.h>
#include <string.h>

int compareHuffNode(const void *a, const void *b){
    int temp = ((LHuffNode*)a)->weight-((LHuffNode*)b)->weight;
   
    return temp==0?0:-temp/abs(temp);
}

//创建哈夫曼树(通过字典创建HUFFMAN树)
LHuffTree *createHuffmanTree(LDictionary *dict){
    
    LHuffTree *tree = (LHuffTree*)malloc(sizeof(LHuffTree));

    tree->size = dict->size;
    tree->nodecount = tree->size * 2 - 1;
    tree->height = 0;
    tree->codes = NULL;
    tree->nodes = (LHuffNode*)malloc(sizeof(LHuffNode) * tree->nodecount);

    //将字典中的键值对转为森林
    for(int i = 0; i < dict->size; i++){
        tree->nodes[i].weight = dict->arr[i].value;
        tree->nodes[i].ch = dict->arr[i].key;
        tree->nodes[i].parent = -1;
        tree->nodes[i].left = -1;
        tree->nodes[i].right = -1;
    }

    //跟据weight对所有树的根节点排序
    quickSort(tree->nodes, tree->size, sizeof(LHuffNode), compareHuffNode);

    //不断取两颗根节点权重最小的树构成新的树,直到森林只剩一棵树
    for(int i = 0; tree->size-2-i>=0; i++){
        memcpy(&tree->nodes[tree->nodecount-2*(i+1)], &tree->nodes[tree->size-2-i], 2*sizeof(LHuffNode));
        int newnode_weight = tree->nodes[tree->nodecount-2*(i+1)].weight + tree->nodes[tree->nodecount-2*(i+1)+1].weight;
        int j;
        for(j=tree->size-3-i; j>=0&&tree->nodes[j].weight<newnode_weight ; j--);
   
        if(j!=tree->size-3-i)
            memcpy(&tree->nodes[j+2], &tree->nodes[j+1], sizeof(LHuffNode)*((tree->size-3-i)-j));

        tree->nodes[j+1].weight = newnode_weight;
        tree->nodes[j+1].left = tree->nodecount-(2*(i+1));
        tree->nodes[j+1].right = tree->nodecount-(2*(i+1))+1;
        tree->nodes[j+1].ch = 0;

    }

    //连接所有节点的父节点
    for(int i = 0; i < tree->nodecount; i++){
        if(tree->nodes[i].left!=-1)
            tree->nodes[tree->nodes[i].left].parent = i;
        if(tree->nodes[i].right!=-1)
            tree->nodes[tree->nodes[i].right].parent = i;
    }

    //计算哈弗曼树的高度
    int height = 1;
    for(int curindex = tree->nodecount-1;tree->nodes[curindex].parent!=-1;height++,curindex=tree->nodes[curindex].parent);
    tree->height = height;

    // printf("height:%d\n", height);

    // for(int i = 0; i < tree->nodecount; i++)
    //     printf("%d: left:%d, right:%d, parent:%d, ch:%c\n", i, tree->nodes[i].left, tree->nodes[i].right, tree->nodes[i].parent, tree->nodes[i].ch);
    // printf("\n");

    return tree;
}

//跟据哈夫曼树生成哈夫曼编码
LHuffCode* createHuffmanCode(LHuffTree *tree){
    LHuffCode *huffcodes = (LHuffCode*)malloc(sizeof(LHuffCode)*tree->size);
    memset(huffcodes, 0, sizeof(LHuffCode)*tree->size);

    char*temparr = (char*)malloc(sizeof(char)*tree->height);
    int templen;

    int curcode_num=0;

    for(int i = 1; i < tree->nodecount; i++){
        memset(temparr, 0, sizeof(char)*tree->height);
        templen = 0;

        huffcodes[curcode_num].code = (char*)malloc(sizeof(char)*tree->height);
        memset(huffcodes[curcode_num].code, 0, sizeof(char)*tree->height);

        if(tree->nodes[i].ch == 0)
            continue;

        //从叶子节点开始向上遍历,生成编码
        for(int curindex = i; tree->nodes[curindex].parent!=-1; curindex=tree->nodes[curindex].parent){
            int parent = tree->nodes[curindex].parent;

            if(tree->nodes[parent].left == curindex){
                temparr[templen++] = '1';
            }else{
                temparr[templen++] = '2';
            }

        }

        //反转编码,并保存
        for(int j = 0; j < templen; j++){
            huffcodes[curcode_num].code[j] = temparr[templen-1-j];
        }
        huffcodes[curcode_num].ch = tree->nodes[i].ch;

        curcode_num++;

    }

    tree->codes=huffcodes;

    return huffcodes;
}

//释放哈夫曼树
void freeLHuffmanTree(LHuffTree *tree){
    if(tree->nodes != NULL)
        free(tree->nodes);

    if(tree->codes != NULL){
        for(int i = 0; i < tree->size; i++){
            if(tree->codes[i].code != NULL)
                free(tree->codes[i].code);
        }
        free(tree->nodes);
    }
    free(tree);
}

#ifndef _LHUFFTREE_H_
#define _LHUFFTREE_H_

#include "LDictionay.h"


struct _HuffNode
{
    char ch;
    int weight;
    int parent,left,right;
};
typedef struct _HuffNode LHuffNode;

struct _HuffCode
{
    char ch;
    char *code;
};
typedef struct _HuffCode LHuffCode;

struct _HuffTree
{
    LHuffNode *nodes;
    LHuffCode *codes;
    int size;
    int nodecount;
    int height;
};
typedef struct _HuffTree LHuffTree;



//创建哈夫曼树(通过字典创建HUFFMAN树)
LHuffTree *createHuffmanTree(LDictionary *dict);

//跟据哈夫曼树生成哈夫曼编码
LHuffCode* createHuffmanCode(LHuffTree *tree);

//释放哈夫曼树
void freeLHuffmanTree(LHuffTree *tree);


#endif /* _LHUFFTREE_H_ */

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值