哈夫曼树(Huffman Tree)

//
// Created by dgm on 19-3-16.
//
#include 
#include 
using namespace std;
typedef struct HNode{
    HNode(int w,int p,int l,int r)
    :weight(w),
    parent(p),
    lchild(l),
    rchild(r)
    {}
    unsigned int weight;
    unsigned int parent,lchild,rchild;
}HNode,*HuffmanTree;
typedef char** HuffmanCode;     //保存n个huffman编码
void Select(HuffmanTree HT,int n,int &s1,int &s2)   //从未被合并过得元素中找到权值最小的两个
{
    for (int i = 1; i <= n; ++i) {
        if(!HT[i].parent){
            s1=i;break;
        }
    }
    for (int i = s1+1; i <= n; ++i) {
        if(!HT[i].parent){
            s2=i;break;
        }
    }
    for (int i = s2; i <= n; ++i) {
        if(!HT[i].parent&&HT[i].weight<=HT[s1].weight){
            s2=s1;s1=i;
        }
    }
}
void HuffmanCoding(HuffmanTree&HT,HuffmanCode&HC,int *w,int n)
{
    int m=2*n-1;
    HT=(HuffmanTree)malloc((m+1)* sizeof(HNode));   //分配空间,由于第一个元素保存在HT[1]而非HT[0]中,
                                                    //所以申请m+1个空间
    HuffmanTree p;
    int i=0;
    for (i=1,p=HT+1;i<=n;i++,p++,w++) *p={*w,0,0,0};    //元素保存在叶子节点中(编号1-n)
    for (;i<=m;i++,p++) *p={0,0,0,0};                   //非叶节点(n+1-m)
    for (i=n+1; i<=m ; ++i) {             //从第一个非叶节点开始
        int s1,s2;
        Select(HT,i-1,s1,s2);
        HT[s1].parent=i,HT[s2].parent=i;  //两个最小元素合并后
        HT[i].lchild=s1,HT[i].rchild=s2;  //形成一个新的节点,再参与到与其余元素的合并中去
        HT[i].weight=HT[s1].weight+HT[s2].weight;
    }
    //到这里,树就建好了,接下来遍历这个数得到叶子节点的编码
    HC=(HuffmanCode)malloc((n+1)* sizeof(char*));   //HC[i]存储第i个元素的编码
    char *cd=(char*)malloc(n* sizeof(char));        //cd作临时变量,记录编码后存入HC

    for (i=1; i<=n; i++) {
        cd[n-1]='\0';   //后边的strcpy是以cd[start]的地址为参数,所以要标记结束位置
        int c,f;
        int start=n-1;
        //下边是从树的最底层(或者叶子)回到根节点,并在这个过程中得到编码
        for (c=i,f=HT[i].parent; f; c=f,f=HT[f].parent) {//从第一个元素开始
            if (HT[f].lchild==c)cd[--start]='0';   //如果元素是爸爸的左孩子,则标0
            else cd[--start]='1';                  //如果是右孩子,则标1
            //因为是从叶子到根,所以--start(前置--),这样以后,按从cd[start]到cd[n-1]的顺序
            //得到的恰好是按从根到叶子的编码(而不是从叶子到根)
        }
        HC[i]=(char*)malloc((n-start)* sizeof(char));   //实际编码位数所需空间
        strcpy(HC[i],&cd[start]);       //复制到HC[i]
    }
    free(cd);   //过河拆桥
    for (i = 1; i <= n; ++i) {  //输出看看,应该正确
        cout<<"the Huffman Code of "<<i<<" is "<<HC[i]<<endl;
    }
}
int main()
{
    //这里为了简便,将元素的值和权重设成一样的了,
    //也可以用一个结构体分别保存值和权重(例如值为E,权重为0.7)
    //然后按照权重对值进行编码    
    int n=5;
    int *w;
    for (int i = 1; i <= n; ++i) {
        w[i]=i;
    }
    HuffmanTree HT;
    HuffmanCode HC;
    HuffmanCoding(HT,HC,w,n);
    return 0;
}

你可能感兴趣的:(数据结构与算法,数据结构基础)