#include <iostream>
using namespace std;
#define MAX 50
#define MAXNUM 60
typedef struct //哈夫曼树结点结构
{
char data;
int weight;
int parent;
int lchild;
int rchild;
}HuffNode;
typedef struct
{
char cd[MAX]; //存放字符的编码
int start; //编码的起始位置
}HuffCode;
void Select(HuffNode huffTree[], int k, int& i1, int& i2) {
/*选择根结点权值最小的两个结点。*/
int i, j;
for (i = 0; i < k; i++)
if (huffTree[i].parent == -1) { i1 = i; break; }
for (j = i + 1; j < k; j++)
if (huffTree[j].parent == -1) { i2 = j; break; }
for (i = 0; i < k; i++)
if ((huffTree[i].parent == -1) && (huffTree[i].weight < huffTree[i1].weight) && (i2 != i))
{
i1 = i;
}
for (j = 0; j < k; j++)
if ((huffTree[j].parent == -1) && (huffTree[j].weight < huffTree[i2].weight) && (i1 != j))
{
i2 = j;
}
}
void HuffmanTree(HuffNode huffTree[], int n) {
/*此处完成构造哈夫曼树huffTree []*/
int i, k;
// 初始化
for (i = 0; i < 2 * n - 1; i++)
{
huffTree[i].parent = -1;
huffTree[i].lchild = -1;
huffTree[i].rchild = -1;
}
#if 0
for (k = n; k < 2 * n - 1; k++) {
int i1, i2;
Select(huffTree, k, i1, i2);
/* 在 huffTree [0] ~ huffTree [k-1] 的范围内选择两个parent为-1且
weight最小的结点,其序号分别赋值给i1、i2返回 */
huffTree[k].weight = huffTree[i1].weight + huffTree[i2].weight;
huffTree[i1].parent = k; huffTree[i2].parent = k;
huffTree[k].lchild = i1; huffTree[k].rchild = i2;
}
#else
//优化算法
/*
// 基本思想:先排序,然后每次前面在顺序取权值,k+1和后面新增的比较,
// 如果前面k+1比后面小,取前面k 和 k+1,且取完相加等到新的 i_12,
// 如果后面的比k+1小,则取k 和 后面的 i_12-1 相加得到新的i_12
1. 排序
2. 依次选2个相加得到最小权值
2.1 判断k++是否 大于等于n,如果是则退出
*/
// 排序
HuffNode temp;
for (int i = 0; i < n - 1; ++i)
{
for (int j = i + 1; j < n; ++j)
{
if (huffTree[i].weight > huffTree[j].weight)
{
temp = huffTree[i];
huffTree[i] = huffTree[j];
huffTree[j] = temp;
}
}
}
int i1, i2;
// i1, i2 之和的下标
int i_12 = n - 1;
for (k = 0; k < n ; k++) {
i_12++;
i1 = k;
// 如果i_12存在,判断 i_12 与 k+1 的权值大小
if (huffTree[i_12 - 1].weight < huffTree[k + 1].weight && huffTree[i_12 - 1].lchild != -1)
i2 = i_12 - 1;
else
{
// index 的权值大于 i1+1, 选择小的权值
i2 = ++k;
if (i2 >= n)
{
// 表示i1 是最后一个值,与i_12进行相加,得到最终值
i2 = i_12 - 1;
huffTree[i_12].weight = huffTree[i1].weight + huffTree[i2].weight;
huffTree[i1].parent = i_12; huffTree[i2].parent = i_12;
huffTree[i_12].lchild = i1; huffTree[i_12].rchild = i2;
break;
}
else
{
// 第一次只有1个权值和
if (k > 2)
{
huffTree[i_12].weight = huffTree[i1].weight + huffTree[i2].weight;
huffTree[i1].parent = i_12; huffTree[i2].parent = i_12;
huffTree[i_12].lchild = i1; huffTree[i_12].rchild = i2;
i1 = i_12;
i2 = i_12 - 1;
i_12++;
}
}
}
huffTree[i_12].weight = huffTree[i1].weight + huffTree[i2].weight;
huffTree[i1].parent = i_12; huffTree[i2].parent = i_12;
huffTree[i_12].lchild = i1; huffTree[i_12].rchild = i2;
}
#endif
}
char* strcut(char* dest, char* src, int start)
{
/*
功能: 截取start 后面的字符串
*/
if (dest == NULL || src == NULL)
return NULL;
char* pdst = (char*)dest;
char* psrc = (char*)src + start;
if (start > 0)
{
while (*psrc != '\0')
{
*pdst++ = *psrc++;
if (*psrc == '\0')
{
*pdst = '\0';
break;
}
}
}
else
{
dest = psrc;
}
return dest;
}
void Encoding(HuffNode ht[], HuffCode hcd[], int n)
{
//此处完成哈夫曼编码以及输出哈夫曼编码
// 计算 n 字符的 编码 左为0, 右为1
// 每个叶子结点即为一个字符(数组前n个结点)
// 从第一个结点开始找
for (int i = 0; i < n; ++i)
{
//编码的起始位置
hcd[i].start = n - 1;
hcd[i].cd[hcd[i].start] = '\0';
// c 表示当前结点
int c = i;
// f 表示当前结点的父结点
int f = ht[i].parent;
while (f != -1) // 根结点退出循环
{
if (ht[f].lchild == c)
// 当前孩子结点是当前父节点的左孩子,则编码0
hcd[i].cd[--hcd[i].start] = '0';
else
// 当前孩子结点是当前父节点的左孩子,则编码1
hcd[i].cd[--hcd[i].start] = '1';
// 循环直到根结点
c = f;
f = ht[f].parent;
}
//hcd[i] = strcpy(hcd[i].cd, &cd[start])
char* dest = new char[n - hcd[i].start];
dest = strcut(dest, hcd[i].cd, hcd[i].start);
cout << ht[i].data << ": " << dest << endl;
}
}
int main()
{
int n, i;
HuffNode huffTree[MAXNUM];//创建huffTree类型的一维数组,用于存储哈夫曼树
HuffCode hcd[MAXNUM];//创建hcd类型的一维数组,每个数组元素存储一个叶子结点的哈夫曼编码
cout << "请输入字符个数" << endl;
cin >> n;
for (i = 0; i < n; i++)
{
cout << "输入第" << i + 1 << "个字符:";
cin >> huffTree[i].data;
cout << "输入第" << i + 1 << "个字符的权值:";
cin >> huffTree[i].weight;
}
HuffmanTree(huffTree, n);//构造哈夫曼树
Encoding(huffTree, hcd, n);//求得哈夫曼树huffTree的对应的哈夫曼编码,并输出每个叶子结点的哈夫曼编码
return 0;
}
哈夫曼树生成优化与哈夫曼编码的实现
最新推荐文章于 2024-05-18 16:23:00 发布