哈夫曼树的重要定理
对于具有n个叶子节点的哈夫曼树,一共需要2*n-1个节点。。
因为对于二叉树来说,有3种类型节点,即度数(节点拥有的子树的个数被称为节点的度)为2的节点,和度数为1的节点和度数为0的节点。而哈夫曼树的非叶子节点都是由两个节点合并产生,所以不会出现度数为1的节点。而生成的非叶子节点的个数为叶子节点个数-1,因此n个叶子节点的哈夫曼树,一共需要2*n-1个节点。
#include
using namespace std;
typedef struct
{
unsigned int weight; //结点的权值
unsigned int parent, lcd, rcd; //结点的双亲,左孩子和右孩子的下标
}HTNode,*HuffmanTree;
typedef char** HuffmanCode;
//在HT[1...i-1]中选择parent=0且weight最小的两个结点
int minl(HuffmanTree t, int i)
{
//函数void select()调用
int j, flag;
unsigned int k = 1e9;//取K为不小于可能的值
for (j = 1; j <= i; j++)
{
if (t[j].weight < k && t[j].parent == 0)
k = t[j].weight, flag = j;
t[flag].parent = 1;
return flag;
}
}
void Select(HuffmanTree t, int i, int& s1, int& s2)
{
//s1为最小的两个值中序号小的那个
int j;
s1 = minl(t, i);
s2 = minl(t, i);
if (s1 > s2)
{
j = s1;
s1 = s2;
s2 = j;
}
}
//w存放n个字符的权值(均>0)构造哈夫曼树HT,并取出n个字符的哈夫曼树编码HC
void HuffmanCoding(HuffmanTree& HT, HuffmanCode& HC, int* w, int n)
{
if (n <= 1)
return;
int m = 2 * n - 1;
int i, s1, s2;
HT = (HuffmanTree)malloc((m+1)*sizeof(HTNode));
HuffmanTree p;
for (p = HT + 1, i = 1; i <= n; ++i, ++p, ++w)
{
p->weight = *w;
cout << *w << " ";
p->parent = 0;
p->lcd = 0;
p->rcd = 0;
}
cout << endl;
for (i = n + 1; i <= m; ++i, ++p)
{
p->weight = 0;
p->parent = 0;
p->lcd = 0;
p->rcd = 0;
}
cout << "Try to print the initial huffman Tree table." << endl;
for (int i = 1; i <= m; ++i)
{
cout << HT[i].weight << " " << HT[i].parent << " " << HT[i].lcd << " " << HT[i].rcd << endl;
}
for (int i = 1; i <= m; ++i)
{
Select(HT, i - 1, s1, s2);
HT[s1].parent = i;
HT[s2].parent = i;
HT[i].lcd = s1;
HT[i].rcd = s2;
HT[i].weight = HT[s1].weight + HT[s2].weight;
}
cout << "Try to print the created huffman Tree table." << endl;
for (int i = 1; i <= m; ++i)
{
cout << HT[i].weight << " " << HT[i].parent << " " << HT[i].lcd << " " << HT[i].rcd << endl;
}
HC = (HuffmanCode)malloc((n + 1) * sizeof(char*));
char* cd = (char*)malloc(n * sizeof(char));
cd[n - 1] = '<= 1)
return;
int m = 2 * n - 1;
int i, s1, s2;
HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode));
HuffmanTree p;
for (p = HT + 1, i = 1; i <= n; i++, p++, w++)
{
p->';
int start, c, f;
for (i = 1; i <= n; i++)
{
start = n - 1;
for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)
{
if (HT[f].lcd == c)
cd[--start] = '0';
else
cd[--start] = '1';
}
HC[i] = (char*)malloc((n - start) * sizeof(char));
strcpy(HC[i], &cd[start]);
free(cd);
}
}
void HuffmanCoding2(HuffmanTree& HT, HuffmanCode& HC, int* w, int n)
{
//w存放n个字符的权值(均>0)构造哈夫曼树HT,并求出n个字符的哈夫曼树编码HC
if (n <= m; i++, p++)
{
p->weight = *w;
p->parent = 0;
p->lcd = 0;
p->rcd = 0;
}
for (i = n + 1; i <= m; i++)
{
Select(HT, i - 1, s1, s2);
HT[s1].parent = i;
HT[s2].parent = i;
HT[i].lcd = s1;
HT[i].rcd = s2;
HT[i].weight = HT[s1].weight + HT[s2].weight;
}
HC = (HuffmanCode)malloc((n + 1) * sizeof(char*));
int q = m;
char* cd = (char*)malloc(n * sizeof(char));
int cdlen = 0;
for (i = 1; i <= m; ++i)
HT[i].weight = 0;
while (q)
{
if (HT[q].weight == 0)
{
HT[q].weight = 1;
if (HT[q].lcd != 0)
{
q = HT[q].lcd;
cd[cdlen++] = '0';
}
else if (HT[q].rcd == 0)
{
HC[q] = (char*)malloc((cdlen + 1) * sizeof(char));
cd[cdlen] = '
';
strcpy(HC[q], cd);
}
}
else if (HT[q].weight == 1)
{
HT[q].weight = 2;
if (HT[q].rcd != 0)
{
q = HT[q].rcd;
cd[cdlen++] = '1';
}
}
else
{
HT[q].weight = 0;
q = HT[q].rcd;
cd[cdlen++] = '1';
}
}
}
int main()
{
HuffmanTree HT;
HuffmanCode HC;
int n;
int data[1000];
while (scanf("%d", &n) != EOF)
{
for (int i = 1; i <= n; ++i)
{
scanf("%d", &data[i]);
}
cout << endl;
HuffmanCoding2(HT, HC, data + 1, n);
for (int i = 1; i <= n; ++i)
{
printf("%s\n", HC[i]);
}
delete(HC);
delete(HT);
}
return 0;
}weight = 0;
p->parent = 0;
p->lcd = 0;
p->rcd = 0;
}
for (i = n + 1; i
构建哈夫曼树
原理
构造思路
1.初始化:首先申请2n个单元,然后循环2n-1次,从1号单元开始,依次将1至2n-1所有单元中的双亲,左右孩子的下标都初始化为0;最后循环n次,输入前n个单元中叶子结点的权值
2.创建树:循环n-1次,通过n-1次的选择、删除与合并来创建哈夫曼树。选择是从当前森林中选择双亲为0且权值最小的两个树根结点s1和s2的权值和作为一个新结点的权值依次存入到数组的第n+1之后的单元中,同时记录这个新结点左孩子的下标为s1,右孩子的下标为s2。
<= 1)return;
int m = 2 * n - 1;
int i, s1, s2;
HT = new HTNode[m + 1]; //0号单元未用,所以需要动态分配m+1个单元,HT[m]表示根结点
for (i = 1; i <= m; ++i)
{
HT[i].parent = 0;
HT[i].lcd = 0;
HT[i].rcd = 0;
}
for (int i = 1; i <= n; ++i) //输入前n个单元中叶子结点的权值
cin ><= m; ++i)
{
Select(HT, i - 1, s1, s2);
//在HT[k](1<=k<=i-1)中选择两个其双亲域为0且权值最小的结点,并返回它们在HT中的序号s1和s2
HT[s1].parent = i;
HT[s2].parent = i;
//得到新结点i,从森林中删除s1,s2,将s1和s2的双亲域由0改为i
HT[i].lcd = s1;
HT[i].rcd = s2; //s1,s2分别作为i的左右孩子
HT[i].weight = HT[s1].weight + HT[s2].weight; //i的权值作为左右孩子权值之和
}
}
void CreateHuffmanTree(HuffmanTree& HT, int n)
{
//构造哈夫曼树HT的初始化工作
if (n
> HT[i].weight;
//构造哈夫曼树
for (i = n + 1; i
根据哈夫曼树求哈夫曼编码
①分配存储n个字符编码的编码表空间HC,长度为n+1; 分配临时存储每个字符编码的动态数组空间cd,cd[n-1]置为\0'(哈夫曼树最高n-1层,最多只有n-1个分支,即编码最多只有n-1位)。
②逐个求解n个字符的编码,循环n次,执行以下 *** 作:
●设置变量start用于记录编码在cd中存放的位置,start初始时指向最后,即编码结束符位置n-1;
●从叶子结点向上回溯至根结点,求得字符i的编码,当f没有到达根结点时,循环执行以下 *** 作:继续向上回溯,改变c和f的值。若结点c是f的左孩子,则生成代码0,否则生成代码1,生成的代码0或1保存在cd[start]中;
回溯一次start向前指一个位置,即--start;
③释放临时空间cd\
void CreatHuffmanCode(HuffmanTree HT, HuffmanCode& HC, int n)
{
char* cd = (char*)malloc(n * sizeof(char));
HC = new char* [n + 1]; //分配存储n个字符编码的编码表空间
cd = new char[n]; //分配临时存放每个字符编码的动态数组空间
cd[n - 1] = ''; //编码结束符
int start, i,c,f;
for (i = 1; i <= n; ++i) //逐个字符求哈夫曼编码
{
start = n - 1; //start开始时指向最后,即编码结束符位置
c = i; f = HT[i].parent; //f指向结点c的双亲结点
while (f != 0) //从叶子结点开始向上回溯,直到根结点
{
--start; //回溯一次,start向前指一个位置
if (HT[f].lcd == c)cd[start] = '0'; //结点c是f的左孩子,则生成代码0
else cd[start] = '1'; //结点c是f的右孩子,则生成代码1
c = f; f = HT[f].parent; //继续向上回溯
} //求出第i个字符的编码
HC[i] = new char[n - start]; //为第i个字符编码分配空间
strcpy(HC[i], &cd[start]); //将求得的编码从临时空间cd复制到HC的当前行中
}
delete cd; //释放临时空间
}
文件的编码和解码
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)