问题描述:
根据给定的n个节点的权重建立一颗哈夫曼树,并构造哈夫曼编码
需求:
要求构造一个有n个节点的哈弗曼树,根据二叉树的性质,整个二叉树共有2n-1个节点,可用大小为2n-1的向量来存储,将哈夫曼数向量ht中的2n-1个节点进行初始化
将n个节点的权值存储向量ht的前n个分量中
对n个节点进行n-1次合并,新成哈夫曼树
根据哈夫曼树构造哈夫编码,方法是每个叶子节点,反复查找该节点的双亲节点,每步都判断该节点是双亲节点的左孩子还是右孩子(左孩子记为0,右孩子记为1),直到双亲节点,编码结束
解析:
哈夫曼树 距离越近权重越大 距离约远权重越小 做小右大的原则编排哈夫曼树
代码
#include <stdio.h>
#include <stdlib.h>
#define MaxNode 100
//注解一
typedef int HuffmanCode;
//定义了一个结构体 `HTNode`,表示哈夫曼树的结点
typedef struct HTNode{
int weight;
int parent;
int lchild,rchild;
HuffmanCode code;
}HTNode,*HuffmanTree;
void Select(HuffmanTree *HT,int n,int *s1,int *s2){//选最小且没爹的两个
int i;//unsigned不看符号位,故unsigned一般表示的是非负数
unsigned int min=9999;
int temp1=0,temp2=0;
for(i=1;i<=n;i++){
if((*HT)[i].parent==0&&(*HT)[i].weight<min){
min=(*HT)[i].weight;
temp1=i;
}
}
*s1=temp1;
min=9999;
for(i=1;i<=n;i++){
if((*HT)[i].parent==0&&(*HT)[i].weight<min&&i!=temp1){
min=(*HT)[i].weight;
temp2=i;
}
}
*s2=temp2;
}
void CreateHuffmanTree(HuffmanTree *HT,int n){
int i,j,k=0,m,s1,s2;
int a[10];//此数组用来存编码
if(n<=1)return;
m=2*n-1;//n个结点构造成哈夫曼树需2*n-1个结点
(*HT)=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//用[1,m]
for(i=1;i<=m;i++){//赋初值
(*HT)[i].lchild=0;
(*HT)[i].rchild=0;
(*HT)[i].parent=0;
(*HT)[i].code=-1;
}
for(i=1;i<=n;i++){scanf("%d",&(*HT)[i].weight);}
for(i=n+1;i<=m;i++){
Select(HT,i-1,&s1,&s2);//挑最小的两个
(*HT)[s1].parent=i;
(*HT)[s2].parent=i;
(*HT)[i].lchild=s1;(*HT)[s1].code=0;
(*HT)[i].rchild=s2;(*HT)[s2].code=1;
(*HT)[i].weight=(*HT)[s1].weight+(*HT)[s2].weight;
}
for(i=1;i<=n;i++){
j=i;
printf("%d的编码:",(*HT)[j].weight);
while((*HT)[j].parent!=0){
a[k]=(*HT)[j].code;
j=(*HT)[j].parent;
k++;
}//因未用二维数组,故存完直接打印输出,接着用于下一把
while(k!=0){
printf("%d",a[k-1]);
k--;
}printf("\n");
}
}
void main(){
int i,m,n=6;//1 4 6 8 9 14
HuffmanTree HT;
CreateHuffmanTree(&HT,n);
m=2*n-1;
printf("结点:");
for(i=1;i<=m;i++){printf("%d ",HT[i].weight);}
system("pause");
}
chatgpt详细注释版本代码
#include <stdio.h>
#include <stdlib.h>
#define MaxNode 100 // 定义最大结点数
typedef int HuffmanCode; // 定义哈夫曼编码类型
typedef struct HTNode{ // 定义哈夫曼树结点类型
int weight; // 权值
int parent; // 父结点
int lchild, rchild; // 左右子结点
HuffmanCode code; // 编码
} HTNode, *HuffmanTree;
void Select(HuffmanTree *HT, int n, int *s1, int *s2){
// 选取权值最小且没有父结点的两个结点
int i;
unsigned int min = 9999; // 初始化最小值
int temp1 = 0, temp2 = 0; // 初始化最小结点编号
for(i = 1; i <= n; i++){
// 遍历所有结点,找到权值最小且没有父结点的结点
if((*HT)[i].parent == 0 && (*HT)[i].weight < min){
min = (*HT)[i].weight;
temp1 = i;
}
}
*s1 = temp1; // 将最小结点编号赋给s1
min = 9999; // 重新初始化最小值
for(i = 1; i <= n; i++){
// 遍历所有结点,找到权值次小且没有父结点的结点
if((*HT)[i].parent == 0 && (*HT)[i].weight < min && i != temp1){
min = (*HT)[i].weight;
temp2 = i;
}
}
*s2 = temp2; // 将次小结点编号赋给s2
}
void CreateHuffmanTree(HuffmanTree *HT, int n){
// 创建哈夫曼树
int i, j, k = 0, m, s1, s2;
int a[10]; // 存储编码
if(n <= 1) return; // 结点数小于等于1,直接返回
m = 2 * n - 1; // 哈夫曼树的结点数
*HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode)); // 分配哈夫曼树结点空间
for(i = 1; i <= m; i++){
// 初始化哈夫曼树结点
(*HT)[i].lchild = 0;
(*HT)[i].rchild = 0;
(*HT)[i].parent = 0;
(*HT)[i].code = -1;
}
for(i = 1; i <= n; i++){
scanf("%d", &(*HT)[i].weight); // 读入权值
}
for(i = n + 1; i <= m; i++){
Select(HT, i - 1, &s1, &s2); // 选取最小的两个结点
(*HT)[s1].parent = i; // 设置父结点
(*HT)[s2].parent = i;
(*HT)[i].lchild = s1; (*HT)[s1].code = 0; // 设置左右子结点和编码
(*HT)[i].rchild = s2; (*HT)[s2].code = 1;
(*HT)[i].weight = (*HT)[s1].weight + (*HT)[s2].weight; // 设置权值
}
for(i = 1; i <= n; i++){
j = i;
k = 0;
printf("%d的编码:", (*HT)[j].weight);
while((*HT)[j].parent != 0){
a[k] = (*HT)[j].code; // 存储编码
j = (*HT)[j].parent;
k++;
}
while(k != 0){
printf("%d", a[k - 1]); // 逆序输出编码
k--;
}
printf("\n");
}
}
void main(){
int i, m, n = 6; // 初始化结点数和权值
HuffmanTree HT;
CreateHuffmanTree(&HT, n); // 创建哈夫曼树
m = 2 * n - 1;
printf("结点:");
for(i = 1; i <= m; i++){
printf("%d ", HT[i].weight); // 输出所有结点的权值
}
system("pause");
}