哈夫曼树分析以及代码实现

Huffman树又叫做最优二叉树,常常会涉及到树的带权路径长度的概念,即WPL的概念,同时又经常会考到haffman编码及其代码实现方式

下面描述下haffman算法的基本思想:

1、把w1、w2......wn构建成n个只有根节点的二叉树

2、选出n个子树中节点值最小的两个子树,合并成一个子树,节点的权值为两个子树的节点和

3、把新的节点加入到原先的子树中,重复1,2的操作直到只剩下一棵树,这个就是haffman树

haffman编码简单介绍:

哈夫曼编码(Huffman Coding)是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫作Huffman编码(有时也称为霍夫曼编码)。

haffman编码的获取的方式:

因为开始的时候是从所有的节点中选取权值最小的节点开始的,而且有权值的节点都是叶子节点,所以必须从叶子节点开始遍历,从而需要知道各个节点的父亲节点的原因,而且获取的编码是逆序的,最后还需要通过逆序操作实现正确的haffman编码的获取

结合严蔚敏数据结构和算法的haffman那章的图6.22的那个例子实现haffman树的构建和haffman编码的获取的C++代码如下:

#include <iostream>
using namespace std;

const int MaxValue = 10000;
const int MaxBit = 10;  //最大的编码位数
const int NodeNum = 10; //测试节点数

struct HaffNode{
    int weight;
    int visited;
    int parent;
    int leftchild;
    int rightchild;
};
struct CodeNode{
    int codeBit[MaxBit];
    int start;  //标记haffman编码的位数
    int weight;
};

void Haffman(int weight[],int n,HaffNode haffTree[]){
    //建立haffman树
    int j,min1,min2,index1,index2;
    //haffman树初始化
    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].visited = 0;
        haffTree[i].leftchild = -1;
        haffTree[i].rightchild = -1;
    }
    //haffman树构造
    for(int i=0;i<n-1;i++){
        min1 = min2 = MaxValue;
        index1 = index2 = 0;
        for(j=0;j<n+i;j++){     //找到最小的两个节点,注意因为合并后新的节点加入所以为j<n+i
            int door = min1>=min2?min1:min2;    //阙值
            if(haffTree[j].weight<tempMin && haffTree[j].visited==0){
                if(min1>=min2){
                    min1 = haffTree[j].weight;
                    index1 = j;
                }else{
                    min2 = haffTree[j].weight;
                    index2 = j;
                }
            }
        }//end for 并且合并两个最小的节点为一个新的节点
        haffTree[index1].parent = n+i;
        haffTree[index2].parent = n+i;
        haffTree[index1].visited = 1;
        haffTree[index2].visited = 1;
        haffTree[n+i].weight = haffTree[index1].weight+haffTree[index2].weight;
        haffTree[n+i].leftchild = index1;
        haffTree[n+i].rightchild = index2;
    }
}

void haffmanCode(HaffNode haffTree[],int n,CodeNode haffCode[]){
    //由n个节点的haffman树构造haffman编码
    CodeNode *node = new CodeNode();
    int child,parent;
    for(int i=0;i<n;i++){
        node->start = 0;
        node->weight = haffTree[i].weight;
        child = i;
        parent = haffTree[child].parent;
        //由叶节点逆向到根节点
        while(parent!=0){
            if(haffTree[parent].leftchild==child){
                node->codeBit[node->start++] = 0;
            }else{
                node->codeBit[node->start++] = 1;
            }
            child = parent;
            parent = haffTree[child].parent;
        }
        for(int j=node->start-1;j>=0;j--){  //获取从根节点到叶子的haffman序列
            haffCode[i].codeBit[node->start-j-1] = node->codeBit[j];
        }
        haffCode[i].start = node->start;
        haffCode[i].weight = node->weight;
    }
}

int main(){
    int n = 4,total = 0;//测试数据,用的是严蔚敏书的图6.22那个数据
    int weight[] = {5,7,4,2};
    HaffNode *haffTree = new HaffNode[2*n-1];
    CodeNode *haffCode = new CodeNode[n];
    Haffman(weight,n,haffTree);
    haffmanCode(haffTree,n,haffCode);
    //输出节点的haffMan编码
    for(int i=0;i<n;i++){
        cout<<"weight = "<<haffCode[i].weight<<" Code = ";
        for(int j=0;j<haffCode[i].start;j++){
            cout<<haffCode[i].codeBit[j];
        }
        total += haffCode[i].weight*haffCode[i].start;
        cout<<endl;
    }
    cout<<"The WPL is: ";
    cout<<total<<endl;
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现哈夫曼树的需求分析通常包括以下几个步骤: 1. **问题识别**: 首先,确定需求是为了创建一个高效的编码方案,比如用于数据压缩,哈夫曼编码就是基于字符出现频率设计的。 2. **用户群体**: 哈夫曼树的应用广泛,可能包括软件开发(数据存储)、文本处理(词典编码)、图像编码等领域。用户可能是程序员、数据科学家或对压缩算法感兴趣的个人。 3. **功能描述**: - 输入:字符及其出现频率的列表。 - 输出:构建的哈夫曼树结构(节点表示字符,权值表示频率)及对应的编码表。 - 功能:添加新字符、查找编码、进行编码/解码操作。 4. **性能需求**: - 时间效率:对于频繁的编码和解码操作,应能快速完成。 - 空间效率:编码表占用的空间应合理,特别是内存限制下。 5. **错误处理**: - 输入验证:确保输入是有效的字符频率数据,处理无效或缺失数据。 - 算法正确性:确保哈夫曼树的构建过程符合标准算法(如贪心构造,合并最小权值节点等)。 6. **可扩展性**: - 设计应能支持动态插入/删除字符,以及在线编码/解码。 7. **接口设计**: - 明确接口定义,如函数原型,参数类型,返回值类型等。 8. **兼容性**: 如果是在特定环境(如嵌入式系统)下实现,要考虑硬件限制和资源消耗。 在实施需求分析后,你可以继续进行设计阶段,制定详细的算法和数据结构,然后编写代码实现这些功能。如果你需要具体的代码示例或者更深入的讨论,请告诉我。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值