Huffman树的定义与实现

使用静态链表与伪指针(即数组)实现Huffman树

//
//  main.cpp
//  HuffmanTree
//
//  Created by Cyril on 2016/12/8.
//  Copyright © 2016年 Cyril. All rights reserved.
//

#include <iostream>
#include <string>
#include <cfloat>
#define MAXSIZE 1005
using namespace std;
//霍夫曼树结点类
template <class T>
class HTNode
{
public:
    T data;
    double weight;
    int parent;
    int lChild;
    int rChild;
};
//霍夫曼编码类
class HCode
{
public:
    char code[MAXSIZE];//存放当前结点的霍夫曼编码
    int start;//用start来存放霍夫曼编码的最开始字符
};

//霍夫曼树
//对于具有n个叶子结点的霍夫曼树,共有2n-1个结点,ht[0~n-1]存放叶子结点,ht[n~2n-2]存放需要构造的非叶子结点
template <class T>
class HT
{
private:
    int wnum;//权值个数
    HTNode<T> ht[MAXSIZE];//存放霍夫曼树
    HCode hCode[MAXSIZE];//存放霍夫曼编码
public:
    void SetValue(T *data, double *weight, int len);//设置初值
    void CreateHT();//构造霍夫曼树
    void Encode();//求霍夫曼编码
    void DispHCode();//输出霍夫曼编码
    void Decode(string str);//根据编码求数据
};
template <class T>
void HT<T>:: SetValue(T *data, double *weight, int len) {
    for (int i=0; i<len; i++) {
        ht[i].data=data[i];
        ht[i].weight=weight[i];
    }
    wnum=len;
}
template <class T>
void HT<T>:: CreateHT() {
    int lNode,rNode;//存放左结点与右结点
    double min1,min2;//存放两个最小的权值
    for (int i=0; i<(2*wnum-1); i++)
        ht[i].parent=ht[i].lChild=ht[i].rChild=-1;//初始化都赋值为-1
    for (int i=wnum; i<(2*wnum-1); i++) {
        min1=min2=DBL_MAX;//初始化最大值
        lNode=rNode=-1;//lNode与rNode为两个权值最小的结点位置
        for (int j=0; j<=i-1; j++)
            if (ht[j].parent==-1) {//遍历根结点
                if (ht[j].weight<min1) {//找出新的最小值
                    min2=min1;
                    rNode=lNode;
                    min1=ht[j].weight;
                    lNode=j;
                } else if (ht[j].weight<min2) {//找到次小值
                    min2=ht[j].weight;
                    rNode=j;
                }
            }
        ht[lNode].parent=ht[rNode].parent=i;//合并为同一个父亲结点
        ht[i].weight=ht[lNode].weight+ht[rNode].weight;
        ht[i].lChild=lNode;
        ht[i].rChild=rNode;//ht[i]即是父亲结点
    }
}
template <class T>
void HT<T>:: Encode() {
    int c,p;//c存放孩子的位置,p存放父亲的位置,用于递推循环
    for (int i=0; i<wnum; i++) {//遍历叶子结点
        hCode[i].start=wnum;//从hcode[i].code[wnum]开始放置霍夫曼编码,按照逆序
        c=i;
        p=ht[i].parent;
        while (p!=-1) {//循环直到无父亲结点,即根结点
            if (ht[p].lChild==c)
                hCode[i].code[hCode[i].start]='0';//若该结点为左孩子结点,编码置为0
            else
                hCode[i].code[hCode[i].start]='1';//若该结点为右孩子结点,编码置为1
            hCode[i].start--;
            c=p;
            p=ht[p].parent;
        }
        hCode[i].start++;//返回一位,存放编码最开始字符

    }
}
template <class T>
void HT<T>:: DispHCode() {
    cout<<"The Huffman codes are: "<<endl;
    for (int i=0; i<wnum; i++) {
        cout<<ht[i].data<<':';
        for (int j=hCode[i].start; j<=wnum; j++) {
            cout<<hCode[i].code[j];
        }
        cout<<endl;
    }
}
template <class T>
void HT<T>:: Decode(string str) {
    int len=(int)str.length();
    int i=0,j=2*wnum-2;//下标指针,i用于遍历str字符串,j用来遍历树,树的根结点为2*wnum-2
    T temp=0;//存取读取的数据
    while (len--) {
        temp=((str[i]=='0')?ht[ht[j].lChild].data:ht[ht[j].rChild].data);//左右孩子的数据
        j=((str[i]=='0')?ht[j].lChild:ht[j].rChild);
        i++;
    }
    if(temp)
        cout<<"The data you wanted is: "<<temp<<endl;
    else
        cout<<"Can't find the data you wanted!"<<endl;
}
int main()
{
    string str;
    HT<char> HFMTree;
    double w[4]={7,5,2,4};
    char d[4]={'a','b','c','d'};
    HFMTree.SetValue(d,w,4);
    HFMTree.CreateHT();
    HFMTree.Encode();
    HFMTree.DispHCode();
    cout<<"Please input the code: ";
    cin>>str;
    HFMTree.Decode(str);
    return 0;
}

程序运行结果如下:

程序运行结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值