Description
由键盘输入一组整数,作为权值序列,求赫夫曼编码并输出。Input输入为两行数据,第一行是一个整数,作为输入权值的个数( n< =10),第二行为权值序列。Output输出为权值序列对应的赫夫曼编码,每个编码输出一行
Sample Input
4
4 3 2 1
Sample Output
4:0
3:10
2:110
1:111
#include <bits/stdc++.h>
#define Max_size 1005
using namespace std;
typedef struct
{
int weight;
int parent, lc, rc;
} HTnode, *HuffTree;
typedef char **Huffcode;
void select(HuffTree HT, int n, int &s1, int &s2)
{
int m1, m2, cnt = 0;
for (int i = 1; i <= n; i++)
{
if (HT[i].parent == 0)
{
if (cnt == 0)
m1 = i;
if (cnt == 1)
m2 = i;
cnt++;
if (cnt == 2)
break;
}
}
// cout << m1 << m2 << "\n";
for (int i = 1; i <= n; i++)
{
if (HT[i].parent == 0 && i != m1 && i != m2)
{
if (HT[i].weight < HT[m1].weight && HT[i].weight > HT[m2].weight)
{
m1 = m2;
m2 = i;
}
else if (HT[i].weight < HT[m1].weight && HT[i].weight < HT[m2].weight)
{
if (HT[m1].weight < HT[m2].weight)
{
m2 = i;
}
else
{
m1 = m2;
m2 = i;
}
}
else if (HT[i].weight > HT[m1].weight && HT[i].weight < HT[m2].weight)
{
m2 = i;
}
else if (HT[i].weight == HT[m1].weight)
{
if (HT[m1].weight < HT[m2].weight)
{
m2 = i;
}
}
else if (HT[i].weight == HT[m2].weight)
{
if (HT[m1].weight > HT[m2].weight)
{
m1 = m2;
m2 = i;
}
}
}
}
s1 = m1;
s2 = m2;
}
void selectpro(HuffTree HT, int n, int &s1, int &s2)
{ // 按左小又大
int k1 = -1, k2; // 分别记录一趟的最小的两个结点
for (int j = 1; j <= n; j++)
{ // 更新k1,k2为前两个不为空的结点
if (HT[j].parent == 0 && k1 == -1)
{
k1 = j;
continue;
}
if (HT[j].parent == 0)
{
k2 = j;
break;
}
}
for (int j = k2; j <= n; j++)
{ // 找到前两个最小的结点并记录
if (HT[j].parent == 0)
{
if (HT[j].weight < HT[k1].weight)
{
k2 = k1;
k1 = j;
}
else if (HT[j].weight < HT[k2].weight)
{
k2 = j;
}
}
}
s1 = k1;
s2 = k2;
}
void selectHT(HuffTree HT, int n, int &s1, int &s2)
{ // 按先后顺序
int i, m1 = 1, m2 = 1;
for (i = 1; i <= n; i++)
{ // 先找到最小的
if (HT[i].parent == 0)
{
if (HT[m1].weight > HT[i].weight)
m1 = i;
}
}
for (i = 1; i <= n; i++)
{
if (HT[i].parent == 0 && i != m1)
{ // 再找第二小的
if (HT[m2].weight > HT[i].weight && m2 != m1)
m2 = i;
if (m2 == 1) // 如果找完m2没有动,说明只有两个父亲结点为0
m2 = i;
}
}
// 使s1和s2是先后顺序
if (m1 > m2)
swap(m1, m2);
s1 = m1;
s2 = m2;
}
void Huffman(HuffTree &HT, Huffcode &HC, int *w, int n)
{
if (n <= 1)
return;
int m = n * 2 - 1, i, start, c, f;
HT = (HuffTree)malloc((m + 1) * sizeof(HTnode));
for (i = 1; i <= n; i++)
{ // 初始化哈夫曼树
HT[i].weight = w[i];
HT[i].lc = HT[i].parent = HT[i].rc = 0;
}
for (; i <= m; i++) // 初始化父亲结点
HT[i].weight = HT[i].lc = HT[i].parent = HT[i].rc = 0;
for (i = n + 1; i <= m; i++)
{
int s1, s2;
// 查找该趟父亲结点为0且权值最小的两个点(可以是左小右大也可以按先后顺序)
selectHT(HT, i - 1, s1, s2);
HT[s1].parent = i; // 两个孩子的父节点为i
HT[s2].parent = i;
HT[i].lc = s1; // 记录左右孩
HT[i].rc = s2;
HT[i].weight = HT[s1].weight + HT[s2].weight; // 更新权值
}
HC = (Huffcode)malloc((n + 1) * sizeof(char *)); // 给编码分配n+1个空间
char *cd; // 给辅助分配n个空间
cd = (char *)malloc(n * sizeof(char));
cd[n - 1] = '\0'; // 下标从0开始,所以n-1应该为结束符
for (i = 1; i <= n; i++)
{
start = n - 1;
for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)
{ // 根据父亲结点左0右1
if (HT[f].lc == c)
{
start--;
cd[start] = '0';
}
else
{
start--;
cd[start] = '1';
}
}
// 这里必须只分配n-start个空间,这样输出的时候较为方便
HC[i] = (char *)malloc((n - start) * sizeof(char));
strcpy(HC[i], &cd[start]);
}
}
int main()
{
HuffTree HT;
Huffcode HC;
int n, *w;
w = new int[Max_size];
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> w[i];
}
Huffman(HT, HC, w, n);
for (int i = 1; i <= n; i++)
{
cout << w[i] << ":";
cout << HC[i] << "\n";
}
return 0;
}