哈夫曼树与哈夫曼编码

哈夫曼编码描述:

        哈夫曼编码利用字符的使用频率来编码,采用不定长的编码方法,使经常使用的字符编码较短,而不经常使用的字符编码较长;

        哈夫曼编码有两个特点:

        1、编码尽可能短,使用频率越高,编码越短;

        2、编码不能有二义性,一个字符的编码不能是另一个字符编码的前缀。

哈夫曼树的构建:

    1、首先定义结点类,每一个结点有5个成员:权值(使用频率)、父亲、左孩子、右孩子、本身的值;

class Node
{
public:
    double weight;  //权值
    int father;
    int lchile;
    int rchile;
    char value;   //结点本身的值
};

    2、建立结点类型的数组,若字符的个数最大为N,共需要存放2N-1个元素

Node huff_node[MAX_NODE * 2 - 1];   //算上新生成的结点,需要存储2n-1个结点

    3、构建树:

        首先,将所有2n-1个结点对象全部初始化,父亲和左右孩子用-1,然后根据输入,保存前n个结点的权值和代表的字符;

        之后,每次在当前没有父亲的结点中选出两个权值最小的结点,权值最小的结点作为左孩子,权值次小的结点作为右孩子,构建一棵新树。

        父亲的权值为左右孩子的权值之和,每次构建新树需要更改5个成员:左右孩子的父亲、父亲的左右孩子,父亲权值;共需要构建n-1次(n-1个新生成的结点)。

void CreateHuffmanTree(Node* node,const int& n)
{
    double m1 = 0, m2 = 0;  //用于存放最小权值和次小权值
    int x1 = 0, x2 = 0;
    for (int i = 0; i < 2 * n - 1; i++)
    {
        node[i].weight = 0;
        node[i].father = -1;
        node[i].lchile = -1;
        node[i].rchile = -1;
    }
    for (int i = 0; i < n; i++)
    {
        cout << "请输入第" << i + 1 << "个结点以及权值:" << endl;
        cin >> node[i].value >> node[i].weight;
    }
    
    for (int i = 0; i < n - 1; i++)   //要构建剩下的n-1个结点
    {
        m1 = m2 = 0x7fffffff;
        x1 = x2 = -1;
        for (int j = 0; j < i + n; j++)   //在已经构建好的i+n个结点中找出权值最小的两个孤儿结点
        {
            if (node[j].weight < m1 && node[j].father == -1)
            {
                m2 = m1;
                x2 = x1;
                m1 = node[j].weight;
                x1 = j;
            }
            else if (node[j].weight < m2 && node[j].father == -1)
            {
                m2 = node[j].weight;
                x2 = j;
            }
        }
        node[x1].father = n + i;
        node[x2].father = n + i;
        node[n + i].lchile = x1;
        node[n + i].rchile = x2;
        node[n + i].weight = m1 + m2;

    }
}

根据哈夫曼树获取字符哈夫曼编码 :

        1、建立编码类:一个数组类型成员,用于存放一个字符的哈夫曼编码;一个整形变量,用于记录开始读的位置;由于在哈夫曼树中,需要编码的结点都是叶子,适合自底向上,数组从尾部开始插入元素。

class Code
{
public:
    int code[MAX_NODE];   //存储结点的哈夫曼编码
    int start;    //开始的读的下标
};

        2、建立编码类型数组,若输入字符最大个数为N,共N个元素

Code huff_code[MAX_NODE];

        3、获取哈夫曼编码

        定义两个变量c和f,c为当前需要编码的结点下标,f为c的父亲;

        若c为f的左结点,对应字符编码数组的开始位置插入0,反之插入1;然后将编码数组开始位置前移1位,c和f向上回溯一层;重复此过程直至回溯到根,即可求得c代表字符的编码;

        将上述过程重复n次,即可获取n个字符的哈夫曼编码

void GetHuffmanCode(Code* code, const int& n)
{
    int c, f;
    for (int i = 0; i < n; i++)
    {
        huff_code[i].start = n - 1;
        c = i;
        f = huff_node[c].father;
        while (f != -1)
        {
            if (huff_node[f].lchile == c)
            {
                huff_code[i].code[huff_code[i].start] = 0;
            }
            else
            {
                huff_code[i].code[huff_code[i].start] = 1;
            }
            huff_code[i].start--;
            c = f;
            f = huff_node[f].father;
        }
    }
}

总体代码实现:

#include <iostream>
using namespace std;
#define MAX_NODE 100

//结点类
class Node
{
public:
    double weight;  //权值
    int father;
    int lchile;
    int rchile;
    char value;   //结点本身的值
};

//编码类
class Code
{
public:
    int code[MAX_NODE];   //存储结点的哈夫曼编码
    int start;    //开始的读的下标
};

Node huff_node[MAX_NODE * 2 - 1];   //算上新生成的结点,需要存储2n-1个结点
Code huff_code[MAX_NODE];

//构造哈夫曼树
void CreateHuffmanTree(Node* node,const int& n)
{
    double m1 = 0, m2 = 0;  //用于存放最小权值和次小权值
    int x1 = 0, x2 = 0;
    for (int i = 0; i < 2 * n - 1; i++)
    {
        node[i].weight = 0;
        node[i].father = -1;
        node[i].lchile = -1;
        node[i].rchile = -1;
    }
    for (int i = 0; i < n; i++)
    {
        cout << "请输入第" << i + 1 << "个结点以及权值:" << endl;
        cin >> node[i].value >> node[i].weight;
    }
    
    for (int i = 0; i < n - 1; i++)   //要构建剩下的n-1个结点
    {
        m1 = m2 = 0x7fffffff;
        x1 = x2 = -1;
        for (int j = 0; j < i + n; j++)   //在已经构建好的i+n个结点中找出权值最小的两个孤儿结点
        {
            if (node[j].weight < m1 && node[j].father == -1)
            {
                m2 = m1;
                x2 = x1;
                m1 = node[j].weight;
                x1 = j;
            }
            else if (node[j].weight < m2 && node[j].father == -1)
            {
                m2 = node[j].weight;
                x2 = j;
            }
        }
        node[x1].father = n + i;
        node[x2].father = n + i;
        node[n + i].lchile = x1;
        node[n + i].rchile = x2;
        node[n + i].weight = m1 + m2;

    }
}

//获取哈夫曼编码
void GetHuffmanCode(Code* code, const int& n)
{
    int c, f;
    for (int i = 0; i < n; i++)
    {
        huff_code[i].start = n - 1;
        c = i;
        f = huff_node[c].father;
        while (f != -1)
        {
            if (huff_node[f].lchile == c)
            {
                huff_code[i].code[huff_code[i].start] = 0;
            }
            else
            {
                huff_code[i].code[huff_code[i].start] = 1;
            }
            huff_code[i].start--;
            c = f;
            f = huff_node[f].father;
        }
    }
}

//输出哈夫曼编码
void OutputHuffmanCode(const int& n)
{
    for (int i = 0; i < n; i++)
    {
        cout << huff_node[i].value << ": ";
        for (int j = huff_code[i].start + 1; j < n; j++)
        {
            cout << huff_code[i].code[j];
        }
        cout << endl;
    }
}

int main()
{
    int n;
    cout << "请输入结点个数:" << endl;
    cin >> n;
    CreateHuffmanTree(huff_node, n);
    GetHuffmanCode(huff_code, n);
    OutputHuffmanCode(n);

    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可惜浅灰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值