Huffman树编码 DFS实现

本文探讨了Huffman树的构建过程,强调了从n个初始节点经过n-1次迭代生成的Huffman树拥有2*n-1个节点的特点。文章通过深度优先搜索(DFS)来讲解编码方法,并介绍了在Huffman树节点中添加'parents'值以优化处理的技巧。
摘要由CSDN通过智能技术生成

通过写这个编码和huffman树的构建,让我对huffman tree 有了更深的理解:

1:首先huffman是经过n-1次迭代之后生成的树,所以如果开始的节点有n个的话,那麽生成之后的的树的节点个数是2*n-1

2:编码的话可以用DFS处理;

3:树的节点新加了一个parents值,让我学到了一种新的写法。//在挑选最小值的时候需要

#include<iostream>
#include <iomanip>
#include <algorithm>
#include <string>
#include <map>
using namespace std;
struct element
{
    char c=NULL;
    int weight;        // 权值域
    int lchild, rchild, parent;  // 该结点的左、右、双亲结点在数组中的下标
    string code;
};
// 选取权值最小的两个结点
void selectMin(element a[],int n, int &s1, int &s2)
{   int i,j;
    for ( i = 0; i < n; i++)
    {
        if (a[i].parent == -1)// 初始化s1,s1的双亲为-1
        {
            s1 = i;
            break;
        }
    }
    for (; i < n; i++)// s1为权值最小的下标
    {
        if (a[i].parent == -1 && a[s1].weight > a[i].weight)
            s1 = i;
    }
    for (j = 0; j < n; j++)
    {
        if (a[j].parent == -1&&j!=s1)// 初始化s2,s2的双亲为-1
        {
            s2 = j;
            break;
        }
    }
    for (; j < n; j++)// s2为另一个权值最小的结点
    {
        if (a[j].parent == -1 && a[s2].weight > a[j].weight&&j != s1)
            s2 = j;
    }
}
// 哈夫曼算法
// n个叶子结点的权值保存在数组w中
void HuffmanTree(element huftree[], map<char,int> mp, int n)
{
    for (int i = 0; i < 2*n-1; i++)    // 初始化,所有结点均没有双亲和孩子
    {
        huftree[i].parent = -1;
        huftree[i].lchild = -1;
        huftree[i].rchild = -1;
    }
    int i=0;
    for(map<char,int>::iterator iter=mp.begin();iter!=mp.end();iter++){
        huftree[i].c=iter->first;
        huftree[i].weight=iter->second;
        i++;
    }
    for (int k = n; k < 2 * n - 1; k++) // n-1次合并
    {
        int i1, i2;
        selectMin(huftree, k, i1, i2); // 查找权值最小的俩个根节点,下标为i1,i2
        // 将i1,i2合并,且i1和i2的双亲为k
        huftree[i1].parent = k;
        huftree[i2].parent = k;
        huftree[k].lchild = i1;
        huftree[k].rchild = i2;
        huftree[k].weight = huftree[i1].weight + huftree[i2].weight;
    }

}
// 打印哈夫曼树
void print(element hT[],int n)
{
    cout << "index weight parent lChild rChild char code" << endl;
    cout << left;    // 左对齐输出
    for (int i = 0; i < n; ++i)
    {
        cout << setw(5) << i << " ";
        cout << setw(6) << hT[i].weight << " ";
        cout << setw(6) << hT[i].parent << " ";
        cout << setw(6) << hT[i].lchild << " ";
        cout << setw(6) << hT[i].rchild << " ";
        cout << setw(6) << hT[i].c      << " ";
        cout << hT[i].code<<endl;
    }
}
void encode(int index,element huftree[],string code){
    huftree[index].code=code;
    int l=huftree[index].lchild;
    int r=huftree[index].rchild;
    if(l!=-1){
       encode(l,huftree,code+"0");
    }
    if(r!=-1){
       encode(r,huftree,code+"1");
    }
}
int main()
{
    map<char,int> mp;
    mp['A']=8;mp['B']=20;mp['C']=30;mp['D']=15;mp['E']=27;
    int len=mp.size();
    element *hufftree=new element[2*len-1];    // 动态创建数组
    HuffmanTree(hufftree, mp, len);
    encode(2*len-2,hufftree,"");
    print(hufftree,2*mp.size()-1);
    system("pause");
    return 0;
}

 

使用DFSHuffman进行编码,可以按照以下步骤进行: 1. 对于Huffman上的每个叶子节点,给它赋予一个编码,一般用0和1表示,左子赋值为0,右子赋值为1。 2. 从根节点开始遍历Huffman,遇到0就向左走,遇到1就向右走,直到遇到叶子节点,将叶子节点的编码输出。 下面是一个例子: 假设有一个字符串"ABBCCCDDDDEEEEE",按照Huffman编码得到的如下: ``` /\ / \ / \ / \ E(5) /\ / \ / \ D(4) C(3) / \ / \ B(2) A(1) ``` 其中,括号内的数字表示字符出现的次数。 根据Huffman编码的规则,编码值短的字符对应的节点越靠近根节点。因此,我们可以给每个叶子节点赋予一个编码,如下: ``` A: 10 B: 11 C: 0 D: 01 E: 00 ``` 接下来,我们使用DFS遍历Huffman,从根节点开始遍历。假设我们从根节点开始遍历,先遇到的是左子,因此我们输出0,然后进入左子,遇到叶子节点E,输出它的编码00。然后回到根节点,遇到右子,因此我们输出1,然后进入右子,遇到叶子节点D,输出它的编码01。然后回到根节点,遇到右子,因此我们输出1,然后进入右子,遇到叶子节点C,输出它的编码0。然后回到根节点,遇到左子,因此我们输出0,然后进入左子,遇到叶子节点B,输出它的编码11。最后回到根节点,遇到左子,因此我们输出0,然后进入左子,遇到叶子节点A,输出它的编码10。因此,字符串"ABBCCCDDDDEEEEE"的Huffman编码为: ``` 10 11 0 0 0 01 01 01 01 00 00 00 00 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值