#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<limits.h>
#include<string.h>
//int n1 = 0, n2 = 0;
#pragma warning(disable:4996)
struct Huffunode//定义哈夫曼树结点
{
int weight;
int parent;
int lchild;
int rchild;
};
void select(Huffunode huffutree[], int n, int& n1, int& n2)//定义返回数组两个最小值下标,由于用return只能返回一个值故可以使用引用或者全局变量或者结构体
{
int a[1000];//将哈夫曼树中叶节点的权值拷贝到数组a中下标一致
for (int i = 0; i < n; i++)
{
a[i] = huffutree[i].weight;
}
//for(int i=0;i<n;i++)
//printf("%d ", a[i]);
//printf("\n");
int s1 = INT_MAX,s2 = INT_MAX;//初始化两个储存变量为最大值,头文件为limits.h
//printf("%d\n", n);
for (int i = 0; i < n; i++)//选择比较过程,若该数组元素a[i]比s1和s2都小且该结点没有父亲结点parent域为-1则将s2的值改为s1,s1的值改为a[i],n2改为n1,n1改为i
{
if (a[i] < s1 && a[i] < s2&&huffutree[i].parent == -1)
{
s2 = s1;
s1 = a[i];
n2 = n1;//n1,n2为引用变量,形参变实参变
n1 = i;
//printf("%d,%d\n", n1, n2);
}
else if (a[i] > s1&&a[i] < s2&&huffutree[i].parent == -1)//若a[i]比s1大但是比s2小且该结点没有父亲结点parent域为-1则将s2的值改为a[i],n2的值改为i
{
s2 = a[i];
n2 = i;
//printf("%d,%d\n", n1, n2);
}
}
}
void createhuffmantree(Huffunode huffutree[], int w[], int n)//创建哈夫曼树
{
for (int i = 0; i < 2 * n - 1; i++)//初始化,若叶子数为n则哈夫曼树结点数为2n-1.
{
huffutree[i].parent = -1;
huffutree[i].lchild = -1;
huffutree[i].rchild = -1;
}
for (int i = 0; i < n; i++)//给叶子结点赋权值
huffutree[i].weight = w[i];
for (int i = n; i < (2 * n) - 1; i++)//构建过程
{
int n1 = 0, n2 = 0;
select(huffutree, i, n1, n2);//选择已有哈夫曼树结点中两个权值最小且没有双亲的结点
//printf("%d %d\n", n1, n2);
huffutree[i].weight = huffutree[n1].weight + huffutree[n2].weight;//连接
huffutree[n1].parent = i;
huffutree[n2].parent = i;
huffutree[i].lchild = n1;
huffutree[i].rchild = n2;
//printf("%d %d %d %d\n", huffutree[i].weight, huffutree[i].parent, huffutree[i].lchild, huffutree[i].rchild);
}
}
void huffucoding(Huffunode huffutree[], char* huffunode[], int n)//哈夫曼树编码
{
char *temp=(char*)malloc(sizeof(char)*n);//开辟一个长度为n的数组temp
temp[n-1] = '\0';//将最后一个位置储存’\0'结束符,方面用%s输出
for (int i = 0; i < n; i++)
{
int t = 0;
int cur = n-1;//储存哈夫曼码位置
int pos = i;//当前处理结点
int parent = huffutree[i].parent;//当前结点的双亲结点
while (parent != -1)//如果当前结点有双亲则进入循环,从叶子到根逆向编码
{
if (huffutree[parent].lchild ==pos)//当前结点是双亲结点的左孩子编码为0,否则编码为1
{
temp[--cur] =' 0';
t++;
}
else if (huffutree[parent].rchild == pos)
{
temp[--cur] ='1';
t++;
}
pos = parent;//指向下一个结点
parent = huffutree[parent].parent;
}
/*for(int i=0;i<t;i++)
printf(" %d", temp[cur+i]);
printf("\n");*/
//printf("%s\n", &temp[cur]);
huffunode[i] = (char*)malloc(sizeof(char)*(n - cur));//开辟哈夫曼编码长度的数组,并用指针数组的i个元素指向首地址
strncpy(huffunode[i], &temp[cur],n-cur);//将临时开辟temp指向的空间的值拷贝到huffunode[i]指向的区域
}
free(temp);//释放临时开辟的空间
}
int main()//测试
{
Huffunode huffutree[1000];
char* huffunode[1000];
int w []={11,4,6,2,13,25,8,16 };
createhuffmantree(huffutree, w, 8);
printf("哈夫曼树如下:\n");
printf(" 权值 父亲结点序号 左孩子序号 右孩子序号\n");
for (int i = 0; i < 15; i++)
{
printf("下标%2d: %3d %9d %12d %12d\n",i, huffutree[i].weight, huffutree[i].parent, huffutree[i].lchild, huffutree[i].rchild);
}
huffucoding(huffutree,huffunode, 8);
for (int i = 0; i < 8; i++)
{
printf(" %d:%s\n",huffutree[i].weight, huffunode[i]);
}
}
哈夫曼树的创建和哈夫曼编码
最新推荐文章于 2022-08-08 16:24:19 发布