哈夫曼编码 ———哈夫曼树 (数据结构)

哈夫曼编码(数据结构)

哈夫曼编码,又称霍夫曼编码,是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫做Huffman编码(有时也称为霍夫曼编码)

#include<iostream>
#include<stdio.h>
#include<string.h>   //因为使用了strcpy字符串函数
#include<stdlib.h>
typedef struct{       //哈夫曼树的储存   //可以储存在一个一维数组里
int weight;           //结点的权值
int parent,lchild,rchild;    //结点的双亲,左右孩子的下标
}HTNode,*HuffmanTree;         //动态分配数组储存哈夫曼树
typedef char **HuffmanCode;
void Select(HuffmanTree HT,int len,int &s1,int &s2)   //优先级的判断
{
	int i,min1=0x3f3f3f3f,min2=0x3f3f3f3f;//先赋予最大值
	for(i=1;i<=len;i++)
	{
		if(HT[i].weight<min1&&HT[i].parent==0) 
		{
			min1=HT[i].weight;     
			s1=i;  
		}
	}
	int temp=HT[s1].weight;//将原值存放起来,然后先赋予最大值,防止s1被重复选择
	HT[s1].weight=0x3f3f3f3f;
	for(i=1;i<=len;i++)
	{
		if(HT[i].weight<min2&&HT[i].parent==0)
		{
			min2=HT[i].weight;
			s2=i;
		}
	}
	HT[s1].weight=temp;//恢复原来的值
}

   void CreateHuffmanTree(HuffmanTree &HT,int n)  //构建哈夫曼树
   {int s1,m,s2,i;                        //变量的初始化
   if(n<=1) return;                     //叶子数必须大于2
   m=2*n-1;                             //n个叶子有2n-1个结点
   HT=new HTNode[m+1];    //0号单元未用,所以需要动态分配m+1个单元,HT[m]表示根结点
   for(i=1;i<=m;++i){     //将1到m号单元的双亲,左孩子,右孩子的下标都初始化为0
    HT[i].parent=0;
    HT[i].lchild=0;
    HT[i].rchild=0;}
    printf("请输入前%d个单元的叶子结点的权值:",n);  //输入前n个单元的叶子节点的权值
    for(i=1;i<=n;++i)        
       scanf("%d",&HT[i].weight);  
      for(i=n+1;i<=m;++i){        //通过n-1次的选择,删除,和合并来创建哈夫曼树
        Select(HT,i-1,s1,s2);  //在HT[]数组中选择两个其双亲域权值最小的结点,并返回他们在HT中的序号s1和s2
        HT[s1].parent=i;
        HT[s2].parent=i;    //得到新结点i,从森林中删除s1,s2的双亲域由0改为i
        HT[i].lchild=s1;
        HT[i].rchild=s2;    //s1,s2分别作为i的左孩子和右孩子
        HT[i].weight=HT[s1].weight+HT[s2].weight;   //i的权值为左右孩子的权值之和
      }
    }



void CreateHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n){  //从叶子到根逆向求每一个字符的哈夫曼编码,储存在编码表HC中
    char* cd;
    int i,start,c,f;          //变量及指针的定义
HC=new char*[n+1];       //分配储存n个字符编码表的空间
cd=new char[n];         //分配临时存放每个字符编码的动态数组空间
cd[n-1]='\0';          //编码结束符
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].lchild==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;              //释放临时空间
}



void show(HuffmanTree HT,HuffmanCode HC)     //输出对应的哈夫曼编码
{
	for(int i=1;i<=sizeof(HC)+1;i++)
		printf("%d编码为%s\n",HT[i].weight,HC[i]);
}

int main()
{    HuffmanTree HT;            //分配一个哈夫曼树
    HuffmanCode HC;              //分配一个编码表
    int n;
    printf("请输入有多少个叶子结点");
    scanf("%d",&n);
    CreateHuffmanTree(HT,n);      
    CreateHuffmanCode(HT,HC,n);
    show(HT,HC);
    return 0;
}

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值