哈弗曼编码

定义:
它是由n个带权叶子结点构成的所有二叉树中带权路径长度最短的二叉树。因为这种树最早由哈夫曼(Huffman)研究,所以称为哈夫曼树,又叫最优二叉树。
1.初始化:
根据给定的n个权值{w1,w2,…wn}构成n棵二叉树的集合F={T1,T2,..,Tn},其中每棵二叉树Ti中只有一个带权wi的根结点,左右子树均空。
2. 找最小树:
在F中选择两棵根结点权值最小的树作为左右子树构造一棵新的二叉树,且至新的二叉树的根结点的权值为其左右子树上根结点的权值之和。
3. 删除与加入:
在F中删除这两棵树,并将新的二叉树加入F中。
4. 判断:
重复前两步(2和3),直到F中只含有一棵树为止。该树即为哈夫曼树
哈弗曼编码_第1张图片
代码实现:
由于本身节点的特殊性(同时要记录双亲节点和孩子节点)所以这里采用静态链表来实现构造

typedef struct
{
    char data;//存放节点元素
    int weight;//权值
    int parent;//双亲节点下标
    int lch;//左孩子下标
    int rch;//右孩子
}HTNode;

构造哈弗曼树:

void CreateHT(HTNode ht[], int n)
{
    int i, k, lnode, rnode;
    int min1, min2;
    for (i = 0;i < 2 * n - 1;i++) //初始化
        ht[i].parent = ht[i].lch = ht[i].rch = -1;
    for (i = n;i < 2 * n - 1;i++)//建树
    {
        min1 = min2 = 32767;
        lnode = rnode = -1;
        for (k = 0;k < i;k++)//每次寻找一个最小和一个次小权值的节点并将合并后的节点加入森林
            if (ht[k].parent == -1)
            {
                if (ht[k].weight < min1)
                {
                    min2 = min1;
                    rnode = lnode;
                    min1 = ht[k].weight;
                    lnode = k;
                }
                else if (ht[k].weight < min2)
                {
                    min2 = ht[k].weight;
                    rnode = k;
                }
            }
        ht[i].weight = ht[rnode].weight + ht[lnode].weight;//将合并后的双亲节点依次放在数组末端并记录孩子节点
        ht[i].lch = lnode;
        ht[i].rch = rnode;
        ht[lnode].parent = i;//标记双亲节点下标
        ht[rnode].parent = i;
    }
}

构造哈弗曼编码节点:

typedef struct
{
    int cd[100];//存放节点的编码
    int start;//标记编码的开始下标
}HCode;

哈弗曼编码:

void CreateHCode(HTNode ht[], HCode hcd[], int n)
{
    int i, parents, present;
    HCode hc;
    for (i = 0;i < n;i++)
    {
        hc.start = n;//hcd[start]~hcd[n]用于存放编码
        present = i;//从第i个元素依次编码
       parents = ht[i].parent;//记录当前节点的双亲节点下标
        while (parents != -1)//循环直到树根节点
        {
            if (ht[f].lch == present)//当前节点是左孩子记为0
                hc.cd[hc.start--] = 0;
            else
                hc.cd[hc.start--] = 1;//当前节点是右孩子记为1
            present = parents;// 向上循环
            parents = ht[parents].parent;
        }
        hc.start++;//start指向编码开始下标
        hcd[i] = hc;//存放编码
    }
}

你可能感兴趣的:(编码,哈弗曼树)