哈夫曼树的创建及编码

 哈夫曼树的创建:给n个叶子节点及权值,把n个叶子节点看成n个树,由他们组成了森林,每次在森林中找到最小的两个节点,把他们作为新树的左子树右子树,并把这两个节点从森林中删除,把新树节点加进森林,重复操作直到森林中剩余一个或更少的节点;

哈夫曼树编码:从根节点开始,按左子树为'0',右子树为'1'编码,最后找到叶子节点的编码

#include <stdio.h>   
#include <malloc.h>  
#include <conio.h>   
#include <string.h>  
#include <iostream>  
using namespace std;  
  
#define MAX_LENGTH 100//叶子节点的最大数量   
typedef char **HuffmanCode;  
  
typedef struct HTNode{  
    unsigned int weight;//该节点所占的权重   
    unsigned int parent,lchild,rchild;// 该节点的父节点,左孩子,右孩子   
    HTNode(unsigned int a,unsigned int b,unsigned int c,unsigned int d){  
        weight=a,parent=b,lchild=c,rchild=d;  
    }  
}HTNode,*HuffmanTree;  
  
void Select(HuffmanTree HT,int i,int &s1,int &s2){//把没有父节点的所有节点中最小的两个值赋值给s1,s2   
    int j,k = 1;  
    while(HT[k].parent) //找最小的父节点为0,即没有父节点的点   
        k++;  
    s1 = k;  
    for(j = 1;j <= i;j++)  
        if(!HT[j].parent && HT[j].weight<HT[s1].weight)//找父节点为0的所有节点中的最小值,赋给s1     
            s1 = j;  
    k = 1;  
    while(HT[k].parent || k==s1)//找最小的父节点为0,即没有父节点的点,且不等于s1   
        k++;  
    s2 = k;  
    for(j = 1;j <= i;j++)  
        if(!HT[j].parent && HT[j].weight<HT[s2].weight && j!=s1)//找父节点为0的所有节点中的不为s1的最小值,赋给s2   
            s2 = j;  
}  
  
void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n){//创建哈夫曼树   
    if(n<=1) return;//只有一个节点,直接作为根节点返回,其他情况直接返回   
    int m,i,s1,s2,start,c,f;  
    HuffmanTree p;  
    m = 2*n-1;//哈夫曼树的总节点数量   
    for(p = HT+1,i=1;i<=n;i++,p++,w++){//给前n个节点赋值   
        *p=HTNode(*w,0,0,0);  
        cout<<endl<<"HT["<<i<<"].weight="<<p->weight<<"  ";//输出每个节点的权值   
    }  
    for(;i<=m;i++,p++)  
        *p=HTNode(0,0,0,0);//给后面m-n个节点赋值   
    cout<<endl<<endl<<"HuffmanTree is created in following order :";  
    for(i = n+1;i<=m;i++){  
        Select(HT,i-1,s1,s2);//每次选择节点中最小的两个节点作为新树的左子树,右子树;  
        // 把s1,s2作为节点i的左子树,右子树,  
        HT[s1].parent = i,HT[s2].parent = i;//给s1,s2的父节点赋值    
        HT[i].weight=HT[s1].weight+HT[s2].weight;//计算节点i的权重   
        cout<<endl<<"HT["<<s1<<"] and HT[" <<s2<<"] create";  
        cout<<" HT["<<i<<"], weight="<<HT[i].weight;  
    }  
    //从叶子结点到根结点逆向求每个字符的哈夫曼编码  
    HC = (HuffmanCode)malloc((n+1)*sizeof(char *));//为数组HC开辟空间  
    char cd[MAX_LENGTH];    
    cd[n-1]=0;//编码结束符'\0'的ascii码为0   
    cout<<endl<<endl<<"HuffmanTree Code is as follows :"<<endl;  
    for(i=1;i<=n;i++){//逐个字符求哈夫曼编码  
        start = n-1;//指向编码结束的位置   
        //每个节点的左子树编码为'0',右子树编码为'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'   
        HC[i]=(char *)malloc((n-start)*sizeof(char));//为第i个字符编码分配空间,n-start为第i个字符的编码长。   
        strcpy(HC[i],&cd[start]);//从cd复制编码(串)到HC   
        printf("\nHT[%d] node 's  Huffman code is: %s",i,HC[i]);  
    }         
}  
  
int main()  
{  
    HuffmanTree HT;  
    HuffmanCode HC;  
    int n,i;  
    int *w,W[MAX_LENGTH];//W保存叶子节点的权值   
    cout<<endl<<endl<<"HuffmanCoding.cpp";  
    cout<<endl<<"============="<<endl;  
    cout<<endl<<"Please input the number of the element of HuffmanTree (eg.5):";  
    cin>>n;//输入叶子节点的数量   
    for(i = 0;i < n;i++){  
        cout<<"Please input the weight of the "<<i+1<<"th element (eg.8):";  
        cin>>W[i];//输入每个叶子节点的权值   
    }  
    w = W;  
    HuffmanCoding(HT,HC,w,n);//创建n个叶子节点构成的哈夫曼树   
    cout<<endl<<endl<<"...OK!...";//创建成功   
    getch();  
    return 0;  
} 

猜你喜欢

转载自blog.csdn.net/weixin_42754600/article/details/83713223
今日推荐