哈夫曼编码/译码系统

#include
using namespace std;
#include
#include
#define MAX 100000000          /*定义一个无限大的值*/
#include
int m,n;
typedef struct {
    char letter;
    int number;
    char code[];
}Codes;
Codes *q;
/*哈夫曼树类型定义*/
typedef struct Node
{
    char ch;
    int weight;//权值
    int parent,lchild,rchild;//双亲、左孩子、右孩子结点
}HuffmanTree;
typedef char **HuffmanCode; /*存放哈夫曼编码*/
map<char ,int> p;
int Min(HuffmanTree *&HT,int n)
/*返回树中n个结点中权值最小的结点序号*/
{
    int i,flag;
    int f=MAX;                 /*f为一个无限大的值*/
    for(i=1;i<=n;i++)
        if(HT[i].weight<f&&HT[i].parent==0)
            f=HT[i].weight,flag=i;
    HT[flag].parent=1;           /*给选中的结点的双亲结点赋值1,避免再次查找该结点*/
    return flag;
}

void Select(HuffmanTree *HT,int n,int &s1,int &s2)
/*在n个结点中选择两个权值最小的结点序号,其中s1最小,s2次小*/
{
    int t;
    s1=Min(HT,n);
    s2=Min(HT,n);
    if(HT[s1].weight>HT[s2].weight)/*若序号s1的权值大于s2的权值,将两者交换,使s1最小,s2次小*/
    {
        t=s1;
        s1=s2;
        s2=t;
    }
}

void CreateHuffmanTree(HuffmanTree *&HT,int n,Codes *q)
{
    int s1,s2;
    if(n==1)
        return ;
    m=2*n-1;
    HT=(HuffmanTree*)malloc((m+1)*sizeof(HuffmanTree));//0单元未用,所以需要动态分配m+1个单元,HT[m]表示根结点

    for(int i=1;i<=m;i++)
        HT[i].parent=0,HT[i].lchild=0,HT[i].rchild=0;//将1~m号单元中的双亲、左孩子、有孩子的下标都初始化为0
    int k=0;
    map<char ,int>::iterator iter;
    iter=p.begin();
    while(iter!=p.end())
    {

        HT[++k].ch=iter->first;
        HT[k].weight=iter->second;

        iter++;
    }
    for(int i=n+1;i<=m;i++)
    {//通过n-1次的选择、删除、合并来创建哈夫曼树
        Select(HT,i-1,s1,s2);//在HT[k](1<=k<=i-1)中选择2个双亲域为0且权值最小的2个结点,并返回它们在HT中的序号s1和s2
        HT[s1].parent=i;HT[s2].parent=i;
        //得到新结点i,从哈夫曼树中删除s1、s2,将它们的双亲域由0改为1
        HT[i].lchild=s1;
        HT[i].rchild=s2;
        HT[i].weight=HT[s1].weight+HT[s2].weight;
    }

}

void HuffmanTreeCode(HuffmanTree *HT,HuffmanCode &HC,int n)
{
    int start,c,f;
    HC=(char **)malloc((n+1)*sizeof(char *));
    char cd[n];
    cd[n-1]='\0';
    for(int i=1;i<=n;i++)
    {
        start=n-1;//start开始时指向最后,即编码结束符位置,因为编码时是从哈夫曼树的叶子出发,向上回溯至根结点,所以对于每个字符,得到的编码顺序是从右到左
        c=i,f=HT[i].parent;//f指向c的双亲结点
        while(f)
        {
            start--;//回溯一次start向前指一个位置
            if(HT[f].lchild==c)//结点c是f的左孩子,则生成字符0
                cd[start]='0';
            else//结点c是f的右孩子,则生成字符1
                cd[start]='1';
            c=f,f=HT[f].parent;//继续向上回溯
        }
        HC[i]=(char*)malloc((n-start)*sizeof(char));
        strcpy(HC[i],&cd[start]);
    }
    free(cd);
}
void DeHuffmanTreeCode(HuffmanTree *HT)
{
    int i=m;
    char a[100];
    cin>>a;

    for (int j = 0; j <strlen(a) ; ++j) {
        if (a[j]=='0')
            i=HT[i].lchild;
        else
            i=HT[i].rchild;
        if (HT[i].lchild==0&&HT[i].rchild==0)
        {
            cout<<q[i].letter;
            i=m;
        }
    }

}
int main()
{
    HuffmanTree *HT;//定义哈夫曼树
    HuffmanCode HC;//定义哈夫曼编码
    int i;
    cout<<"请输入字符串:"<<endl;
    string a;
    getline(cin,a);
    for ( i = 0; i <a.length() ; ++i) {
        p[a[i]]++;//统计每个字符出现的次数
    }
    n=p.size();//字符的种类数
    q=new Codes[n+1];//存储每个字符的权值和编码


    CreateHuffmanTree(HT,n,q);

    HuffmanTreeCode(HT,HC,n);

    cout<<"字母"<<"\t"<<"权值"<<"\t"<<"编码"<<endl;
    for(i=1;i<=n;i++)
    {   q[i].letter=HT[i].ch;
        q[i].number=HT[i].weight;
        strcpy(q[i].code,HC[i]);

        cout<<q[i].letter<<"\t"<<q[i].number<<"\t"<<q[i].code<<endl;


    }
    DeHuffmanTreeCode(HT);
    /*释放内存空间*/
    for(i=1;i<=n;i++)
        free(HC[i]);
    free(HC);
    free(HT);
    return 0;
}

你可能感兴趣的:(哈夫曼编码/译码系统)