哈夫曼树的创建:给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;
}