HuffmanTree

    一个Huffman编码的C++实现(这是我当助教的班的一个学生实现的,个人觉得做得还不错,所以分享出来)
#include<iostream.h>
#include<string.h>
#include<fstream.h>
#include<math.h>
#define DN 26
#define SIZE 100
template <class Type>
class MinHeap{
public:
    MinHeap(int maxSize);
    MinHeap(Type arr[],int n);
    ~MinHeap(){delete[]heap;}
    int Insert(const Type &x);
    int RemoveMin(Type &x);
    Type DeleteMin();
    int IsEmpty()const{return CurrentSize==0;}
    int IsFull()const{return CurrentSize==MaxHeapSize;}
    void MakeEmpty(){CurrentSize=0;}
private:
    enum{DefaultSize=10};
    Type *heap;
    int CurrentSize;
    int MaxHeapSize;
    void FilterDown(const int start,const int end);
    void FilterUp(int start);
};
template <class Type> MinHeap<Type>::MinHeap(int maxSize){
    MaxHeapSize=DefaultSize<maxSize?maxSize:DefaultSize;//确定堆大小
    heap=new Type[MaxHeapSize];//创建堆空间
    CurrentSize=0;//初始化
}
template <class Type> MinHeap<Type>::MinHeap(Type arr[],int n){//根据给定数组中的数据和大小,建立堆对象
    MaxHeapSize=DefaultSize<n?n:DefaultSize;
    heap=new Type[MaxHeapSize];
    heap=arr;//数组传送
    CurrentSize=n;//当前堆大小
    int currentPos=(CurrentSize-2)/2;//最后非叶
    while(currentPos>=0){//从下到上逐步扩大,形成堆
        FilterDown(currentPos,CurrentSize-1);//从currentPos开始,到CurrentSize-1为止, 调整
        currentPos--;
    }
}
template <class Type> int MinHeap<Type>::Insert(const Type&x){//在堆中插入新元素x
    if(CurrentSize==MaxHeapSize){//堆满
        cout<<"堆已满"<<endl;
        return 0;
    }
    heap[CurrentSize]=x;//插在表尾
    FilterUp(CurrentSize);//向上调整为堆
    CurrentSize++;//堆元素增一
    return 1;
}
template <class Type> void MinHeap<Type>::FilterUp(int start){//从start开始,向上直到0,调整堆
    int j=start,i=(j-1)/2;//i是j的双亲
    Type temp=heap[j];
    while(j>0){
        if(heap[i].root->data.key<=temp.root->data.key)break;
        else{heap[j]=heap[i];j=i;i=(i-1)/2;}
    }
    heap[j]=temp;
}
template <class Type> void MinHeap<Type>::FilterDown(const int start,const int end){
    int i=start,j=2*i+1;
    Type temp=heap[i];
    while(j<=end){
        if(j<end&&heap[j].root->data.key>heap[j+1].root->data.key)j++;
        if(temp.root->data.key<=heap[j].root->data.key)break;
        else{
            heap[i]=heap[j];
            i=j;
            j=2*j+1;
        }
    }
    heap[i]=temp;
}
template <class Type> int MinHeap<Type>::RemoveMin(Type &x){
    if(!CurrentSize){
        cout<<"Heap empty"<<endl;
        return 0;
    }
    x=heap[0];
    heap[0]=heap[CurrentSize-1];
    CurrentSize--;
    FilterDown(0,CurrentSize-1);
    return 1;
}
template <class Type> Type MinHeap<Type>::DeleteMin(){
    if(!CurrentSize){
        cout<<"Heap empty"<<endl;
        return 0;
    }
    Type x=heap[0];
    heap[0]=heap[CurrentSize-1];
    CurrentSize--;
    FilterDown(0,CurrentSize-1);
    return x;
}


template <class Type>
 struct NodeData{
    Type symbol;//结点代表的符号
    int key;//记录频数
    char num;//结点编码
};
template <class Type> class ExtBinTree;
template <class Type> class Element{
friend class ExtBinTree<Type>;
friend class MinHeap<ExtBinTree<Type> >;
public:
    Element<Type>(Type na='^',int f=0,char n='0'){
        data.key=f;
        data.symbol=na;
        data.num=n;
        parent=leftChild=rightChild=NULL;
    }
private:
    NodeData<Type> data;
    Element<Type>*parent,*leftChild,*rightChild;
};
template <class Type> class ExtBinTree{
friend class MinHeap<ExtBinTree<Type> >;
public:
    ExtBinTree(int n=0,Type *s=NULL,Type *name=NULL,Element<Type> *l=NULL):
    root(l),num(n),str(s){
        na=new Type[n];
        na=name;
        fr=new int[n];
        for(int i=0;i<n;i++)fr[i]=0;
        if(str!=NULL)Fre();
    }
    void Modify(ExtBinTree<Type> *bt1,ExtBinTree<Type> *bt2){
        root->parent=NULL;
        root->leftChild=(*bt1).root;
        root->rightChild=(*bt2).root;
        (*bt1).root->parent=(*bt2).root->parent=root;
        (*bt1).root->data.num='0';
        (*bt2).root->data.num='1';
        root->data.key=(*bt1).root->data.key+(*bt2).root->data.key;
    }
    void HuffmanTree();//构造huffman树
    Element<Type>* Find(Type item);//寻找结点的函数
    char* Coding(Type item);//编码函数
    void Fre();//计算字符频数的函数
    void DeCoding(char s[]);//译码函数
    int *GetFr(){return fr;}//返回字符出现的频数
    double Entropy(int m);//求编码的平均码长
private:
    Element<Type> *root;//扩充二叉树的根
    int num;//输入的字符种类数
    Type *str;//输入的字符串
    Type *na;//存放各种字符
    int *fr;//各种字符的频数
};
template <class Type>
void ExtBinTree<Type>::HuffmanTree(){
    int n(0),*f=new int[num];
    char *s=new char[num];
    for(int i=0;i<num;i++){
        if(fr[i]!=0){
            f[n]=fr[i];
            s[n]=na[i];
            n++;
        }
    }
    ExtBinTree<Type> *Node=new ExtBinTree<Type>[n];
    for(i=0;i<n;i++)
        Node[i].root=new Element<Type>(s[i],f[i]);
    MinHeap<ExtBinTree<Type> > hp(Node,n);
    ExtBinTree<Type> first,second;
    for(i=0;i<n-1;i++){//建立huffman树的过程
        hp.RemoveMin(first);//选根权值最小的树
        hp.RemoveMin(second);//选根权值次小的树
        root=new Element<Type>;
        Modify(&first,&second);//建新的根结点
        hp.Insert(*this);//形成新树插入
    }
}
template <class Type> Element<Type>* ExtBinTree<Type>::Find(Type item){//寻找值为item的结点
    Element<Type>*p=root,**s=new Element<Type>*[num+1];
    int top=-1;
    while(!(p==NULL&&top==-1)){
        while(p!=NULL){
            s[++top]=p;
            p=p->leftChild;
        }
        if(top!=-1){
            p=s[top--];
            if(p->data.symbol==item)return p;
            p=p->rightChild;
        }
    }
    return NULL;
}
template <class Type> char* ExtBinTree<Type>::Coding(Type item){
    Element<Type>*p=Find(item);
    if(p==NULL){
        cerr<<"符号未找到!";
        return NULL;
    }
    char *s=new char[num];
    int i=-1;
    while(p!=root){
        s[++i]=p->data.num;
        p=p->parent;
    }
    char *c=new char[i+2];
    for(int j=0;j<=i;j++)
        c[j]=s[i-j];
    c[j]='\0';
    return c;
}
template <class Type> void ExtBinTree<Type>::DeCoding(char s[]){
    int i=0;
    Element<Type>*p=root;
    while(s[i]!='\0'){
        if(s[i]=='0'){
            p=p->leftChild;
            if(p->data.symbol!='^'){
                cout<<p->data.symbol;
                p=root;
            }
        }
        else{
            p=p->rightChild;
            if(p->data.symbol!='^'){
                cout<<p->data.symbol;
                p=root;
            }
        }
        i++;
    }
}
template <class Type> void ExtBinTree<Type>::Fre(){
    int i=0;
    while(*(str+i)!='\0'){
        for(int j=0;j<num;j++)
            if(*(str+i)==na[j])fr[j]++;
        i++;
    }
}
template <class Type> double ExtBinTree<Type>::Entropy(int m){//计算平均码长
    double ent=0;
    int n(0);
    while(str[n]!='\0')n++;
    if(m==0){   
        for(int i=0;i<num;i++)
            if(fr[i]!=0)
                ent+=-double(fr[i])/n*log(double(fr[i])/n)/log(2);
    }
    else if(m==1){
        for(int i=0;i<num;i++)
            if(fr[i]!=0)
                ent+=double(fr[i])/n*strlen(Coding(na[i]));
    }
    else{
        cout<<"错误调用!\n";
        return 0;
    }
    return ent;
}


void main(){
    char  *sym="abcdefghijklmnopqrstuvwxyz";
    char  s[SIZE],a[20],c;
    char *d=new char[5*SIZE];
  
 cout<<"请输入符号序列:";
    cin>>s;
         
    ExtBinTree<char> h(DN,s,sym);
    h.HuffmanTree();
    int i=0;
    cout<<"编码:\n";
    while(s[i]!='\0'){
        cout<<h.Coding(s[i]);
        i++;
    }
    cout<<endl;
    int n=i;
    cout<<"各字符出现的频率及码字:\n";
    int *f=h.GetFr();
    for(i=0;i<DN;i++)
        if(f[i]!=0)
            cout<<sym[i]<<':'<<double(f[i])/n<<'\t'<<h.Coding(sym[i])<<endl;
  
    cout<<"编码平均码长:"<<h.Entropy(1)<<endl;
    i=0;
    cout<<"译码:\n";
    while(s[i]!='\0'){
        if(i==0)d=strcpy(d,h.Coding(s[i]));
        else d=strcat(d,h.Coding(s[i]));
        i++;
    }
    h.DeCoding(d);
    cout<<endl;
}

 

 

posted on 2008-12-18 19:32  小橋流水  阅读(403)  评论(1编辑  收藏  举报

导航