今天主要是学了一下对于哈夫曼树的编程,并输出其哈夫曼编码
哈夫曼树的存储结构:
typedef struct{
int weight; //表示该结点的权值
int parent,lchild,rchild; //存储该结点的父节点序号、左孩子结点序号、右孩子结点序号
}HTNode,*HuffmanTree;
哈夫曼编码:
char **HC;
函数:创建哈夫曼树
输入:哈夫曼树结点的结构体变量的地址HuffmanTree &HT,还有一个整型数据int n。该结构体变量的成员是int weight; (表示该结点的权值)int parent,lchild,rchild;(存储该结点的父节点序号、左孩子结点序号、右孩子结点序号)。该整型数据是给函数说明有n个叶子结点。
输出:无
优化目标:无
void CreateHuffmanTree(HuffmanTree &HT,int n){
if(n<=1){
return;
}
//因为对于n个叶子结点的哈夫曼树,就会有2*n-1个结点
int m = 2*n-1;
HT = (HuffmanTree)malloc(sizeof(HTNode)*(m+1));
int i,j;
//初始化结点内的值
for(i = 1;i<=m;++i){
HT[i].parent = 0;
HT[i].lchild = 0;
HT[i].rchild = 0;
}
//为这n个结点输入权值
for(i = 1;i<=n;i++){
scanf("%d",&HT[i].weight);
}
//这一段是为了构建哈夫曼树
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;
}
}
函数:在哈夫曼树的创建需要一个选择函数,该选择函数需要在哈夫曼树中找到没有父节点的最小的两个权值的结点序号。
输入:哈夫曼树结点的结构体变量HuffmanTree HT,一个整型数据int n,一个整型数据地址int &s1,一个整型数据地址int &s2。该结构体变量的成员是int weight; (表示该结点的权值)int parent,lchild,rchild;(存储该结点的父节点序号、左孩子结点序号、右孩子结点序号)。该整型数据是给函数说明有n个叶子结点。使用s1和s2的地址,主要是函数的返回值只能有一个,而这里需要两个值,所以直接给函数地址,就可以得到最小的两个序号。
输出:无
优化目标:无
//在哈夫曼树中找最小的两个没有父节点的结点
void Select(HuffmanTree HT,int n,int &s1,int &s2){
int i,min1 = 999,min2 = 999;
s1 = 0;
s2 = 0;
for(i = 1;i<=n;i++){
//首先min1存最小的权值
if(HT[i].parent == 0&&min1>HT[i].weight){
min2 = min1;
s2 = s1;
min1 = HT[i].weight;
s1 = i;
}
else{
//min2存倒数第二小的权值
if(HT[i].parent == 0&&min2>HT[i].weight){
min2 = HT[i].weight;
s2 = i;
}
}
}
}
函数:创建哈夫曼编码
输入:哈夫曼树结点的结构体变量的地址HuffmanTree &HT,还有一个整型数据int n。该结构体变量的成员是int weight; (表示该结点的权值)int parent,lchild,rchild;(存储该结点的父节点序号、左孩子结点序号、右孩子结点序号)。该整型数据是给函数说明有n个叶子结点。
输出:无
优化目标:无
//创建哈夫曼树编码
void CreateHuffmanCode(HuffmanTree HT,int n){
//存储所有哈夫曼叶子结点的编码
HC = (char **)malloc(sizeof(char *)*(n+1));
//存储当前结点的哈夫曼编码
char *cd = (char *)malloc(sizeof(char)*n);
cd[n-1] = '\0';
int i;
for(i = 1;i<=n;i++){
int start = n-1,c = i,f = HT[i].parent;
while(f!=0){
--start;
if(HT[f].lchild == c){
cd[start] = '0';
}
else{
cd[start] = '1';
}
c = f;
f = HT[f].parent;
}
HC[i] = (char * )malloc(sizeof(char)*(n-start));
strcpy(HC[i],&cd[start]);
}
free(cd);
}
函数:输出哈夫曼树
输入:哈夫曼树结点的结构体变量的地址HuffmanTree &HT,还有一个整型数据int n。该结构体变量的成员是int weight; (表示该结点的权值)int parent,lchild,rchild;(存储该结点的父节点序号、左孩子结点序号、右孩子结点序号)。该整型数据是给函数说明有n个叶子结点。
输出:无,该函数的输出是无,但是它会在控制台打印哈夫曼树的每个结点的序号,权值,父节点序号,左右孩子结点序号。
优化目标:无
//输出哈夫曼树
void PrintHuffmanTree(HuffmanTree HT,int n){
int i,m = 2*n-1;
printf("\n");
for(i = 1;i<=m;i++){
printf("%d:\tweight:\t%d \tparent:\t%d \tlchild:\t%d \trchild:\t%d \n",i,HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);
}
}
函数:输出哈夫曼编码
输入:哈夫曼树结点的结构体变量的地址HuffmanTree &HT,还有一个整型数据int n。该结构体变量的成员是int weight; (表示该结点的权值)int parent,lchild,rchild;(存储该结点的父节点序号、左孩子结点序号、右孩子结点序号)。该整型数据是给函数说明有n个叶子结点。
输出:无,该函数的输出为无,但是会依次输出叶子结点的哈夫曼编码
优化目标:无
//输出哈夫曼编码
void PrintHuffmanCode(HuffmanTree HT,int n){
int i;
printf("\n");
for(i = 1;i<=n;i++){
printf("%d:\t%s\n",HT[i].weight,HC[i]);
}
}
main函数中的调用
int main(){
HuffmanTree HT;
int n = 7;
CreateHuffmanTree(HT,n);
CreateHuffmanCode(HT,n);
PrintHuffmanTree(HT,n);
PrintHuffmanCode(HT,n);
return 0;
}
以 给定权值w = {5,7,2,3,6,8,9},构造关于w的一棵哈夫曼树,并输出其哈夫曼编码 为例
输入:
5
7
2
3
6
8
9
输出:
1: weight: 5 parent: 9 lchild: 0 rchild: 0
2: weight: 7 parent: 10 lchild: 0 rchild: 0
3: weight: 2 parent: 8 lchild: 0 rchild: 0
4: weight: 3 parent: 8 lchild: 0 rchild: 0
5: weight: 6 parent: 10 lchild: 0 rchild: 0
6: weight: 8 parent: 11 lchild: 0 rchild: 0
7: weight: 9 parent: 11 lchild: 0 rchild: 0
8: weight: 5 parent: 9 lchild: 3 rchild: 4
9: weight: 10 parent: 12 lchild: 1 rchild: 8
10: weight: 13 parent: 12 lchild: 5 rchild: 2
11: weight: 17 parent: 13 lchild: 6 rchild: 7
12: weight: 23 parent: 13 lchild: 9 rchild: 10
13: weight: 40 parent: 0 lchild: 11 rchild: 125: 100
7: 111
2: 1010
3: 1011
6: 110
8: 00
9: 01
今天完成了哈夫曼树的编程,主要是在输出哈夫曼编码的时候卡了太久了,我将存储哈夫曼编码的变量(char **)直接传到函数里,而函数不知道存储的大小(因为各哈夫曼编码长度不一定是一样的),所以我就将该变量作为全局变量就可以了。明天打算复习点图的内容。