哈夫曼编码C++

基本概念:

1路径:

树中一个结点到另一个结点之间的分支构成这两个结点间的路径

2路径长度:

两结点间路径的分支数

图像展现:

3树的路径长度:

每一个结点的路径长度之和

4权:

将树中结点赋予一个有着某种含义的数值,这个数值称为权

5带权路径长度:

从根结点到该结点间路径长度与该结点权的乘积

6树的带权路径长度:

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

7哈夫曼树:

带权路径最短的二叉树(带权路径最短需要在相同的树中比较)

则哈夫曼树中权越大的叶子离根越近

8哈夫曼算法(构造哈夫曼树的方法):

(1)根据n个给定的权值以每个权值作为根结点的权值构造n棵二叉树森林,每个树只有一个结点

(2)选取两棵根结点权值最小的树作为左右子树,构造一棵新的二叉树,新二叉树根结点权值为左右子树权值之和

(3)删除构成新子树的两棵子树,将新子树加入森林中

(4)重复(2)(3),直到得到最后一棵树,这棵树就是哈夫曼树

口诀:构造森林全是根,选用两小造新树,删除两小添新人,重复二三剩单根

构造哈夫曼树:

原理:

用数组来储存哈夫曼树中各结点的权值,双亲,左右孩子的位置(在数组中的序号)

代码实现:

结点结构:

typedef struct
{
    int weight;
    int parent, lchild, rchild;
}HTNode, * HuffmanTree;

哈夫曼树结构:

void Lowest(HuffmanTree HT, int k/*在数组k之前的数据中比较*/, int &a, int &b/*找到两个权重最小的结点序号存在a,b中*/)
{
    int i;
    for (i = 1; i <= k; i++)
        if (HT[i].parent == 0)
        {
            a = i;break;
        }
    for (i = 1; i <= k; i++)
        if (HT[i].parent == 0 && HT[a].weight > HT[i].weight)
        {
            a = i;
        }
    for (i = 1; i <= k; i++)
        if (HT[i].parent == 0 && i != a)
        {
            b = i;break;
        }
    for (i = 1; i <= k; i++)
        if (HT[i].parent == 0 && HT[b].weight > HT[i].weight && i != a)
        {
            b = i;
        }
}
void CreateHuffmanTree(HuffmanTree &HT, int n/*叶子结点数*/)/*构造哈夫曼树*/
{
    /*初始化哈夫曼树*/
    int m, i;
    if (n <= 1)return;
    m = n * 2 - 1;/*哈夫曼树共有2n-1个结点*/
    HT = new HTNode[m + 1];
    for (i = 1; i <= m; i++)
    {
        HT[i].parent = HT[i].lchild = HT[i].rchild = 0;
    }
    for (i = 1; i <= n; i++)cin >> HT[i].weight;/*输入元素权重*/
    /*构造*/
    int s1, s2;
    for (i = n + 1; i <= m; i++)
    {
        Lowest(HT, i - 1, s1,s2);
        HT[s1].parent = HT[s2].parent = i;
        HT[i].lchild = s1;
        HT[i].rchild = s2;
        HT[i].weight = HT[s1].weight + HT[s2].weight;
    }
}
typedef char** HuffmanCode;

哈夫曼树编码:

原理:

1,统计字符集中每个字符出现的平均概率,概率越大,编码应越短

2,利用哈夫曼树的特点:权越大的叶子离根越近:将每个字符的概率值作为权值,构造哈夫曼树

3,哈夫曼树结点的左分支标0,右分支标1;将根到每个叶子的路径上的标号连接起来,作为该叶子代表的字符的编码

代码实现:
void CreateHuffmanTreeCode(HuffmanTree HT, HuffmanCode& HC, int n)
{
    int i,start,c,f;
    char *cd =new char[n];;
    HC=new char *[n+1];
    cd[n - 1] = '\0';
    for (i = 1; i <= n; i++)
    {
        start = n - 1;
        c = i;
        f = HT[c].parent;
        while (f != 0)
        {
            start--;
            if (HT[f].lchild == c)cd[start] = '0';
            else cd[start] ='1';
            c = f;
            f = HT[f].parent;
        }
        HC[i] = new char[n - start];
        strcpy_s(HC[i],strlen(cd) +1, & cd[start]);
    }
    delete []cd;
}
结果展示:

数据1:

数据2:

数据3:

错误总结:

1strcpy(a,b)

老版本其功能是将b数组复制给a,返回a

vs中不支持strcpy(a,b)函数,编译时会出错

因为如果b数组比a数组大,就会发生错误;应使用strcpy_s(a,n,b),n为中间缓冲区空间,即将b复制到a所需中间储存的内存,一般用strlen(b)+1,可避免缓冲区空间溢出

2动态分配数组空间

声明:如需声明a[n];n为变量,则int a[n]是错误的,该形式只能声明静态常量数组,应该用int new a[n]来定义;

删除:静态数组可用delete来删除,但删除动态数组时会发生错误,系统提示如下

应使用delete[]来删除,如delete [] a;来删除动态数组a[n]

总结:

1哈夫曼树优点:哈夫曼树又称最优二叉树,是带权路径长度最短的二叉树,可用于编码

缺点:哈夫曼编码若用于通讯网络,则延迟较大;对于较短的数据编码意义不大,对于较长数 据,频繁的磁盘访问会降低数据编码速度

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值