您的位置:首页 > 理论基础 > 数据结构算法

数据结构(c)——赫夫曼树与赫夫曼编码

2016-05-03 20:03 591 查看
二叉树的一个重要应用——赫夫曼树(最优二叉树),即所有叶子结点的平均带权路径最短。

赫夫曼算法叙述如下:

(1)根据给定的n个权值{w1,w2,...wn}构成n棵二叉树的集合F={T1,,T2,...,Tn},其中每棵二叉树Ti中只有一个带权为wi的根结点,其左右子树均空;

(2)在F中选取两棵根结点的权值最小的树作为左右子树构造一棵新的二叉树,且置新的二叉树的根结点的权值为其左、右子树上根结点的权值之和;

(3)在F中删除这两棵树,同时将新得到的二叉树加入F中;

(4)重复(2)和(3),直到F只含一棵树为止。这棵树便是赫夫曼树。

程序中赫夫曼用顺序存储结构,赫夫曼编码用二维数组。

定义结构体:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct HTNode{
unsigned int weight;
unsigned int parent,lchild,rchild;
}HTNode,*HuffmanTree;
typedef char **HuffmanCode;
定义函数以及主函数:

void Select(HuffmanTree HT,int n,int &S1,int &S2);
void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n);

main(){
HuffmanTree HT;
HuffmanCode HC;
int w[] = {2,3,1,4};
HuffmanCoding(HT,HC,w,4);
printf("赫夫曼树\n");
for(int i = 1;i <= 7;i ++){
printf("%d,%d,%d,%d\n",HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);
}
printf("赫夫曼编码\n");
for(int i = 1;i <= 4;i ++){
printf("%s\n",HC[i]);
}
}
实现HuffmanCoding函数,以及从赫夫曼树中选择两个权值最小的结点

void Select(HuffmanTree HT,int n,int &S1,int &S2){
//  S1在前,S2在后
S1 = 0;
S2 = 0;
for(int i = 1;i <= n;i ++){
if(HT[i].parent == 0){
S1 = i;
break;
}
}
for(int i = 1;i <= n;i ++){
if(HT[i].parent == 0){
if(HT[i].weight < HT[S1].weight){
S1 = i;
}
}
}					//找到最小权值的下标

for(int i = 1;i <= n;i ++){
if(HT[i].parent == 0){
if(i != S1){
S2 = i;
break;
}
}
}
for(int i = 1;i <= n;i ++){
if(HT[i].parent == 0){
if(HT[i].weight < HT[S2].weight && i != S1){
S2 = i;
}
}
}				//找到第二小权值的下标
if(S1 > S2){
int temp = S1;
S1 = S2; S2 = temp;
}
}

void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n){
//w存在n个权值,构造赫夫曼树HT,并求出n个字符的赫夫曼编码HC
if(n <= 1) return;
int m = 2 * n - 1;
HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode));   //0号单元不用
int i;
HuffmanTree p;
for(p = HT + 1,i = 1;i <= n;++i,++p,++w) {
p->weight = *w; p->parent = 0; p->lchild = 0; p->rchild = 0;
}
for(;i <= m;++i,++p){
p->weight = 0; p->parent = 0; p->lchild = 0; p->rchild = 0;
}
for(i = n+1;i <= m;i++){  //构造赫夫曼树
int S1,S2;
//在HT[1,...,i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2.
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;
}

HC = (HuffmanCode)malloc((n + 1) * sizeof(char *));
char* cd = (char *)malloc(n * sizeof(char));
cd[n - 1] = '\0';       //编码结束符
for(int i = 1;i <= n;i ++){       //逐个求赫夫曼编码
int start = n - 1;            //编码结束符位置
int c;
int f;
for(c = i,f = HT[i].parent;f != 0;c = f,f = HT[f].parent){  //从叶子到根逆向求编码
if(HT[f].lchild == c) cd[--start] = '0';
else cd[--start] = '1';
}
HC[i] = (char *)malloc((n - start) * sizeof(char));
strcpy(HC[i],&cd[start]);     //复制串到HC
}
free(cd);
}
运行结果:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: