15、数据结构预算法 - 哈夫曼编码

哈夫曼编码

 

1、哈夫曼编码思想

首先我们需要一份权重统计,例如学生成绩分布规律


 
 根据统计表构成树,求得其路径长度为20

 
 优化一下,如下图,路径长度就变成了16

 
 计算一下树的WPL 路径长度*权重 的总和
 
 
 优化

 
 哈夫曼编码思想
 假如说字母的权重如下
 A  5
 E  10
 B  15
 D  30
 C  40
 那么先将两个最小的值构成树,这时候N1 就是15。再与相应大小值的B 构成树,N2是30 。再与D 够成树。以此类推,左子树小于右子树(规定)。

 


 2、在实际的传输过程中
 如:传输一段文字

 

根据权重进行构建树
 
 
 N2 现在是28,但是我们还有D 15 和 A 27,都是小于28的,这个时候就要把D 和A 单独在构建成一个二叉树,然后再将N3 N2构建树

 


 构建好的二叉树,原始权重与编码如下图

 
 根据哈夫曼编码思想进行编码

 
 最终得到的结果

 
 
 3、代码实现

#include <stdio.h>
#include "string.h"
#include "stdlib.h"

const int MaxVale = 10000;//初始设定的权重最大值
const int MaxBit = 4;//初始设定的最大编码位数
const int MaxN = 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;
//1、
//根据权重值,构建哈弗曼树;
//{2,4,5,7}
//n = 4;
void Haffman(int weight[],int n, HaffNode* haffTree){
    int j,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;
    }
    
//2、构造哈弗曼树 haffTree 的 n-1个非叶结点
//   每次都找到最小的两个值构建树
    for (int i = 0; i < n-1; i++) {
        m1 = m2 = MaxVale;
        x1 = x2 = 0;
        
        for (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;
            }
        }
    
//      3、将找出的两棵权重最小的树合并为一颗子树
        haffTree[x1].parent = n + i;
        haffTree[x2].parent = n + i;
        
//        将2个节点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;
    }
}
//2、哈夫曼编码
//由n 个结点的哈夫曼树 haffTree 构造哈夫曼编码 haffCode
//{2,4,5,7}
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;
        
    }
    
}

验证

int main(int argc, const char * argv[]) {
    // insert code here...
    printf("Hello, 哈夫曼编码!\n");
    int i, j, n = 4, m = 0;
    
    //权值
    int weight[] = {2,4,5,7};
    
    //初始化哈夫曼树, 哈夫曼编码
    HaffNode *myHaffTree = malloc(sizeof(HaffNode)*2*n-1);
    Code *myHaffCode = malloc(sizeof(Code)*n);
    
    //当前n > MaxN,表示超界. 无法处理.
    if (n>MaxN)
    {
        printf("定义的n越界,修改MaxN!");
        exit(0);
    }
    
    //1. 构建哈夫曼树
    Haffman(weight, n, myHaffTree);
    //2.根据哈夫曼树得到哈夫曼编码
    HaffmanCode(myHaffTree, n, myHaffCode);
    //3.
    for (i = 0; i<n; i++)
    {
        printf("Weight = %d\n",myHaffCode[i].weight);
        for (j = 0; j<myHaffCode[i].start; j++)
            printf("%d",myHaffCode[i].bit[j]);
        m = m + myHaffCode[i].weight*myHaffCode[i].start;
         printf("\n");
    }
    printf("Huffman's WPS is:%d\n",m);
    return 0;
}
Hello, 哈夫曼编码!
Weight = 2
110
Weight = 4
111
Weight = 5
10
Weight = 7
0
Huffman's WPS is:35


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值