1.哈夫曼树
- 几个基本概念:路径 路径长度...
- 什么样的树路径长度(PL)最小?完全二叉树。
- 什么样的树带权路径长度(WPL)最小?哈夫曼树。
- n0 = n2+1,n0+n2 = 2n0-1=n(n0叶子节点,n2非叶子节点,n总叶子节点)
- 哈夫曼树构造算法
/************算法思路******************/ //总节点多少?(记为n) //初始化这些节点(叶子节点置权值x000 for(i:1~n0)剩余的置0000 for(i:~n)) //找到两个parent为0,并且权值最小的节点。 for(i:n+1~m) //把这两个节点的父节点(序号i)置一下,父节点(ht[i])的左右孩子置一下,再置父节点的权值。 /******************************具体代码*************************/ void create_hafumantree(hafumantree ht,int n0,int w[]){ //给出参数 叶子节点权值,叶子节点数 n = 2*n0-1; //i是序号 p是数组,初始化这些节点 for(p = ht,i = 1;i<=n0;i++,p++,w++) *p = {*w,0,0,0}; //? for(;i<=n;i++,p++) *p = {0,0,0,0}; //在i-1的范围里找双亲节点为0且权值最小的两点s1 s2 for(i=n+1;i<=m;i++){ select(ht,i-1,&s1,&s2); ht[s1].parent = i; ht[s2].parent = i; ht[i].Lchild = s1; ht[i].Rchild = s2; ht[i].weight = ht[s1].weight+ht[s2].weight; } ... }
2.哈夫曼树应用(哈夫曼编码)
- 定理1:前缀码
- 定理2:哈夫曼编码是前缀码,是最短、最优前缀码(使带权路径最小)
- 哈夫曼编码算法
/************算法思路***************/ //申请n个字符指针,每个字符指针指向一个数组(竖着给空间hc) //申请cd辅助存储单元,可以放n个字符,最后一位给一个'/0'表结束 (以上准备工作)(横着给空间cd) //for(i:0~n-1) hc[i] = cd; /*PS: 求cd(叶子节点编码)(横着) start指针指向cd最后一位 for(c->child = i,f->c双亲节点 = ht[i].parent;f!=0;c = f,f = ht[f].parent)(横着) 如果是左孩子就置0,否则置1 start指针往前退一位 */ (求哈夫曼码(每个倒着填数)) //(竖着给空间hc)(横着给空间cd) //(求哈夫曼码(倒着填数)) /*****************具体代码***************/ //从叶子节点到根 逆向求每个字符或者指令的 哈夫曼编码 //参数:给出ht(哈夫曼树),n0(叶子节点个数),求hc void CreateHaffmanCode(HaffmanTree ht,HaffmanCode hc,int n0){ hc = (hafumannode)malloc(n0*sizeof(char*)); cd = (char*)malloc(n0*sizeof(char)); //? cd[n0-1] = '\0'; /*hc = new char*[n0+1]; cd = new char[n0];*/ for(int i = 0;i<n;i++){ start = n0-1; for(c = i,f = ht[c].parent;f!=0;c = f,f = ht[f].parent) if(ht[c].Lchild == c) cd[--start]='0'; else cd[--start] = '1'; hc[i] = (char*)malloc(n-start)*sizeof(char)); //? strcpy(hc[i],&cd[start]); /*nc[i] = new char[n-start];*/ } free(cd); }
//指针学的差,关于c的基本知识有所缺漏。无法完全理解。以下另一种较好理解方式。
//给出要构造的哈夫曼树和叶子节点个数
//总节点个数,初始化节点
//找到权值最小节点,认父母,变权值
void CreateHaffmanTree(haffmantree ht,int n0){
if(n<=1) return;
int n = 2*n0-1;
ht = new HTNode[n+1];
for(int i = 1;i<=n;i++){
ht[i].parent = 0;
ht[i].lchild = 0;
ht[i].rchild = 0;
}
for(int i = 1;i<=n0;i++) cin>>ht[i].weight;
for(int i = n0+1;i<=n;i++){
select(ht,i-1,s1,s2);
ht[s1].parent=i; ht[s2].parent=i;
ht[i].lchild = s1;ht[i].rchild = i;
ht[i].weight = ht[s1].weight+ht[s2].weight;
}
}
//很好理解,但是不知道是否有漏洞
void CreateHaffmanCode(HaffmanTree ht,HaffmanCode hc,int n0){
hc = new char*[n0+1];//从序号1开始
cd = new char[n0];//从下标0开始,共n0个空间
cd[n0-1] = '\0';
for(int i = 1;i<=n0;i++){
start = n0-1; //至多占用n0-1个空间,所以共n0个空间
for(int c = i,f = ht[c].parent;f!=0;c = f,f = ht[f].parent)
if(ht[c].lchild == c) cd[--start] = '0';
else cd[--start] = '1';
hc[i] = new char[n0-start];//n0个空间,减去未占用的
strcpy(hc[i],&cd[start]);
}
delete cd;
}