美文网首页
哈夫曼编码

哈夫曼编码

作者: 大橘猪猪侠 | 来源:发表于2020-04-28 15:36 被阅读0次

哈夫曼编码是一种编码方式,该方法依据字符出现概率来构造异字头的平均长度最短的码字,一般就叫做Huffman编码。

哈夫曼思想就是依据使用的频率来最大化的节省字符存储空间。

图1.png

图1是我们求一个分数属于那个阶段的流程判断图

图2.png

图2是利用哈夫曼思想来画出的流程图

我们通过两种方式去求D节点的路程长度值:

图3.png 图4.png

图3和图4是两种方式求的路程值的示意图,从两图中可以很好的得出两种方式哪一种更好。

下面我们通过代码的方式来实现哈夫曼。

1、首先先进行一些基本的变量和结构体设置

const int MaxValue = 10000;//初始设定的权值最大值
const int MaxBit = 4;//初始设定的最大编码位数
const int MaxPoint = 10;//初始设定的最大结点个数

typedef struct HaffNode{
    int weight;
    int flag;
    int parent;
    int leftChild;
    int rightChild;
}HaffNode;

//存放哈夫曼编码的数据元素结构
typedef struct Code{
    int bit[MaxBit];//数组
    int start;//编码的起始下标
    int weight;//字符的权值
}Code;

2、根据权重值,构建哈夫曼树
构建哈夫曼树,先对哈夫曼树进行初始化,由于一些值是由后面两个值相加而存在的节点;因此,我们可以知道数组中拥有的权重值都是叶子节点,根据二叉树原理,可以得到总节点数。
对权重数组进行遍历,找出最小的两个节点,并用一个变量标记值是否有被使用,来得到哈夫曼树

void Haffman(int weight[],int n,HaffNode *haffTree){
    int m1,m2,x1,x2;
    //哈夫曼树初始化
    //n个叶子节点,2n-1个数
    for(int i = 0;i < 2*n-1 ; i++){
        if(i<n)
            haffTree[i].weight = weight[i];
        else
            haffTree[i].weight = 0;

        haffTree[i].parent = 0;
        haffTree[i].flag = 0;
        haffTree[i].leftChild = -1;
        haffTree[i].rightChild = -1;
    }
    

    //构造哈夫曼树的n-1个非叶子节点
    for (int i = 0; i<n-1; i++) {
        m1 = m2 = MaxValue;
        x1=x2=0;
        for (int j = 0; j<n+i; j++) {
            if(haffTree[j].weight<m1&&haffTree[j].flag == 0){
                m2=m1;
                x2=x1;
                m1=haffTree[j].weight;
                x1=j;
            }else if(haffTree[j].weight<m2&&haffTree[j].flag == 0){
                m2 = haffTree[j].weight;
                x2=j;
            }
        }
        //找出两颗权值最小的子树合并为一颗子树
        haffTree[x1].parent = n+i;
        haffTree[x2].parent = n+i;
        //将两个节点的flag标记为1,表示已经加入到哈夫曼树中
        haffTree[x1].flag = 1;
        haffTree[x2].flag = 1;
        //修改节点n+i节点的权值
        haffTree[n+i].weight = haffTree[x1].weight + haffTree[x2].weight;
        //修改n+i的左右孩子值
        haffTree[n+i].leftChild = x1;
        haffTree[n+i].rightChild = x2;
    }
}

3、创建哈夫曼编码元素结构,记录每个节点字符的权重值和编码下标值
由于得到的下标值是逆序的,所有需要对下标值进行逆序置换。

//2、哈夫曼编码
//由n个节点的哈夫曼树haffTree构造的哈夫曼编码haffCode
void HaffmanCode(HaffNode haffTree[],int n,Code haffCode[]){
    //1、创建一个节点cd
    Code *cd = (Code *)malloc(sizeof(Code));
    int child,parent;
    //2、求n个叶子节点的哈夫曼编码
    for (int i = 0; i<n; i++) {
        //从0开始计数
        cd->start = 0;
        //取得编码对应权值的字符
        cd->weight = haffTree[i].weight;
        //当叶子节点i为孩子节点
        child = i;
        //找到child的双亲节点
        parent = haffTree[child].parent;
        //由叶节点向上直到根节点
        while (parent!=0) {
            if(haffTree[parent].leftChild == child){
                cd->bit[cd->start] = 0;//左孩子节点编码0
            }else{
                cd->bit[cd->start] = 1;//右孩子节点编码1
            }
            //编码自增
            cd->start++;
            //当前双亲节点成为孩子节点
            child = parent;
            //找到双亲节点
            parent = haffTree[child].parent;
        }
        int temp = 0;
        for (int j = cd->start-1; j>=0; j--) {
            temp = cd->start-j-1;
            haffCode[i].bit[temp] = cd->bit[j];
        }
        //把cd中的数据赋值到haffCode[i]中
        //保存好haffCode的起始位以及权重值
        haffCode[i].start = cd->start;
        //保存编码对应的权值
        haffCode[i].weight = cd->weight;

    }
}

main函数


printf("哈夫曼编码!\n");
    int n=6,m = 0;
    //权值
    //
    int weight[] = {2,4,6,8,1,9};
    //初始化哈夫曼树,哈夫曼编码
    HaffNode *haffTree = malloc(sizeof(HaffNode)*2*n-1);
    Code *haffCode = malloc(sizeof(Code)*n);
    
    //当前n>MaxN越界,无法处理
    if(n>MaxPoint){
        printf("定义的n越界,修改MaxPoint");
        exit(0);
    }
    //1、构建哈夫曼树
    Haffman(weight, n, haffTree);
    //2、根据哈夫曼树得到哈夫曼编码
    HaffmanCode(haffTree, n, haffCode);
    //3、打印权值
    for (int i = 0; i<n; i++) {
        printf("weight = %d\n",haffCode[i].weight);
        for (int j = 0; j<haffCode[i].start; j++) {
            printf("%d",haffCode[i].bit[j]);
        }
        m = m+haffCode[i].weight*haffCode[i].start;
        printf("\n");
    }
    printf("总哈夫曼值为:%d\n",m);

打印结果:


15880592087214.png

相关文章

网友评论

      本文标题:哈夫曼编码

      本文链接:https://www.haomeiwen.com/subject/fxzvwhtx.html