哈夫曼树编码
里面有哈夫曼树编码过程
完整代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct HtNode
{
int ww;//ww表示权值
int parent;//父节点的下标
int llink;//左孩子的下标
int rlink;//右孩子的下标
};
struct HtTree
{
int m;//叶子结点的个数
int root;//哈夫曼树树根在数组下的下标
struct HtNode* ht;//存放2*m-1个结点的数组
};
typedef struct HtTree* PHtTree;//哈夫曼树类型的指针类型
PHtTree huffman(int m, int* w)//构造具有m个叶子结点的哈夫曼树
{
PHtTree pht;
int i, j, x1, x2, min1, min2;
pht = (PHtTree)malloc(sizeof(struct HtTree));//分配哈夫曼树空间
pht->m = m;
if (pht == NULL)
{
printf("内存分配失败!\n");
exit(EXIT_FAILURE);
}
pht->ht = (struct HtNode*)malloc(sizeof(struct HtNode) * (2 * m - 1));//分配ht数组空间
if (pht->ht == NULL)
{
printf("分配内存失败!\n");
exit(EXIT_FAILURE);
}
for (i = 0; i < 2*m - 1; i++)//初始化ht数组
{
pht->ht[i].llink = -1;
pht->ht[i].rlink = -1;
pht->ht[i].parent = -1;
if (i < m)
{
pht->ht[i].ww = w[i];
}
else
{
pht->ht[i].ww = -1;
}
}
for (i = 0; i < m - 1; i++)//每循环一次构造一个新的内部结点
{
min1 = INT_MAX; min2 = INT_MAX;
x1 = -1; x2 = -1;
for (j = 0; j < m + i; j++)//寻找两个最小权无父结点的结点
{
if (pht->ht[j].ww < min1 && pht->ht[j].parent == -1)
{
min2 = min1;
x2 = x1;
min1 = pht->ht[j].ww;
x1 = j;//x1存放最小权值无父结点的结点下标
}
else if (pht->ht[j].ww<min2&&pht->ht[j].parent==-1)
{
min2 = pht->ht[j].ww;
x2 = j;//x2存放次最小权值的无父结点的结点下标
}
}
pht->ht[x1].parent = m + i;
pht->ht[x2].parent = m + i;
pht->ht[m + i].ww = min1 + min2;
pht->ht[m + i].llink = x1;
pht->ht[m + i].rlink = x2;//构造内部结点
}
pht->root = 2 * m - 2;
return pht;
}
void PrintHuffmanTree(PHtTree T, char* huffCode[])//输出哈夫曼树的结点及哈夫曼编码
{
printf("根节点的下标:%d\n", T->root);
int i;
printf("*****************哈夫曼树的创建过程*******************\n");
printf("权值\tparent(下标)\tllink(下标)\trlink(下标)\n");
for (i =0; i <2*(T->m)-1; i++)
{
printf(" %d\t", T->ht[i].ww);
printf(" %d\t\t", T->ht[i].parent);
printf(" %d\t\t", T->ht[i].llink);
printf(" %d\t\t", T->ht[i].rlink);
printf("\n*******************************************************\n");
}
printf("\n哈夫曼树的编码\n");
int j;
for (j=0;j<T->m;j++)
{
printf("%d %s\n", T->ht[j].ww,huffCode[j]);//输出的编码是按照输入叶子结点的顺序输出的
}
return;
}
void hufufmanCoding(PHtTree T, char* huffCode[], int m)//m是叶子结点的个数(从叶子结点向上建立哈夫曼树编码)
{
char* temp;
int i,start,pos,parent;
temp = new char[m];//存储临时产生的编码串
temp[m - 1] = '\0';
for (i = 0; i < m; i++)
{
start = m - 1;//start是temp数组的尾下标
pos = i;//pos记录正在处理的位置(即当前的位置)
parent = T->ht[i].parent;//找到父节点的下标
while (parent != -1)
{
if (T->ht[parent].llink == pos)//判断当前是左孩子还是右孩子
{//如果是左结点则赋值0
temp[--start] = '0';//start先减减,再赋值
}
else//如果是右结点则赋值1
{
temp[--start] = '1';
}
pos = parent;//把当前位置移到父节点下标的位置
parent = T->ht[parent].parent;//更新父节点
}
huffCode[i] = new char[m - start];//建立哈夫曼编码实际需要的内存空间
strcpy_s(huffCode[i],strlen(&temp[start])+1, &temp[start]);//将临时存储的哈夫曼编码存到huffmanCode中
//printf("%s\n", huffCode[i]);
}
delete temp;//释放temp的空间
}
int main()
{
int m;
printf("请输入叶子结点的个数:\n");
scanf_s("%d", &m);
int w[100] = { 0 };
int i;
printf("请输入叶子结点的权值:\n");
for (i = 0; i < m; i++)
{
scanf_s("%d", &w[i]);
}
PHtTree T;
T=huffman(m,w);
char *huffCode[100] = {};//创建指针数组
hufufmanCoding(T,huffCode,m);
PrintHuffmanTree(T,huffCode);
return 0;
}