计算机小白,欢迎大家一起讨论
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string>
//霍夫曼树结构体
struct HT
{
int weight;//权重
int lchild, rchild, parent;
};
//在1~i-1中找最小的两个值(s1为最小,s2为第二小,若相等则数组h中左侧的为s1
void Find(HT* h, int n, int& s1, int& s2)
{
int i = 2;
for (; i <= n; i++)
{
while (h[s1].parent)//此语句使当次s1被选中后不再被选中
s1++;
if (!h[i].parent)
s1 = h[s1].weight <= h[i].weight ? s1 : i;
}
for (i = 2; i <= n; i++)
{
while (h[s2].parent||s2==s1)//此时s1被选中后还未其父节点赋值,故需排除s1
s2++;
if (!h[i].parent&&i!=s1)
s2 = h[s2].weight <= h[i].weight ? s2 : i;
}
}
void CreateHuffmanTree(HT*& h, int* w,int n)
{
int m = 2 * n - 1;//总结点数
int s1=1, s2=1;
int i = 1;
for (; i <= n; i++,w++)
h[i] = { *w, 0, 0, 0 };
for (; i <= m; i++)
h[i] = { 0, 0, 0, 0 };
for(i=n+1;i<=m;i++)
{
Find(h, i-1, s1, s2);
h[s1].parent = i;
h[s2].parent = i;
h[i].lchild = s1;
h[i].rchild = s2;
h[i].weight = h[s1].weight + h[s2].weight;
}
}
//从根节点遍历霍夫曼树,求各个节点编码
//此处我定向左走为1,向右走为0
void TraverseHuffmanTree(HT*& h, int n, char**& hc)
{
int p = 2 * n - 1;
int length = 0;//当前所求编码长度
char* cd = (char*)malloc(n * sizeof(char));//临时存放编码
//对权重重新赋值,作为标志位使用。
//0代表初次到该节点,应向左走(如果不是叶子节点)
//1代表已经走过左侧了,现在是从左返上来,要去右侧
//2代表从右侧返回,直接退回(因为此节点下放已经遍历完了)
for (int i = 1; i <= p; i++)
h[i].weight = 0;
while (p)
{
if (h[p].weight == 0)
{
h[p].weight = 1;//让他一会向右走
if (h[p].lchild)
{
p = h[p].lchild;
cd[length++] = '1';
}
else
{
cd[length] = '\0';
h[p].weight = 2;//遍历到叶子节点,一会直接返回
hc[p] = (char*)malloc(length * sizeof(char));
strcpy(hc[p], cd);
}
}
else if (h[p].weight == 1)
{ //霍夫曼树是不存在度为1的节点的二叉树,所以如果从左侧返上来,则一定能向右侧走一个
h[p].weight = 2;
p = h[p].rchild;
cd[length++] = '0';
}
else
{
p = h[p].parent;
--length;
}
}
free(cd);
}
void Print(char** hc, int n)
{
for (int i = 1; i <= n; i++)
printf("%s\n", hc[i]);
}
int main()
{
int w[] = { 5,29,7,8,14,23,3,11 };
int n = 8;
HT* h = (HT*)malloc(2*n * sizeof(HT));//存放霍夫曼树节点的数组
CreateHuffmanTree(h, w,n);
char** hc = (char**)malloc(n* sizeof(char*));//指向存放编码字符串首地址的字符指针数组
TraverseHuffmanTree(h,n,hc);
Print(hc, n);
}