haffman哈夫曼编码的实现

<span style="font-size:18px;">/*

  1.在一棵二叉树中,我们定义从A节点到B节点所经过的分支序列为从A节点到B节点的路径;
    定义从A节点到B节点所经过的分支个数为从A节点到B节点的路径长度;
	定义从二叉树的根节点到二叉树中所有叶节点的路径长度之和为该二叉树的路径长度。
  2.如果二叉树中的叶节点都带有权值,则可以把这个定义推广。设二叉树有n歌带权值的叶节点,定义从二叉树的
  根节点到二叉树中所有叶节点的路径长度与相应叶节点权值的乘积之和为该二叉树的带权路径长度。
  WPL=(wi*li)(i从1到n)
  3.我们把具有最小带权路径长度的二叉树称作哈夫曼树或最优二叉树
  4.哈夫曼树构造算法:
     (1):由给定的n个权值{w1,w2,w3,...,wn}构造n棵只有根节点的二叉树,从而得到一个二叉树森林F={T1,T2,T3,....,TN}。
	 (2):在二叉树森林F中选取根节点的权值最小和次小的两棵二叉树作为新的二叉树的左右子树构造新的二叉树,
	     新的二叉手的根节点权值为左右子树根节点权值之和。
	 (3):从二叉树森林F中删除作为新二叉树左右子树的两棵二叉树,将新二叉树加入到二叉树森林F中。
	 (4):重复步骤(2)(3),当二叉树森林F中只剩下一颗二叉树时,这棵二叉树就是所构造的哈夫曼树

  5.哈夫曼树可以用于解决最优化问题。例如电文的编码问题
*/

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#define MaxN 10//初始设定的最大结点个数
#define MaxValue 10000//初始设定的权值最大值
#define MaxBit 4//初始设定的最大编码位数
typedef struct{

	int weight;//权值
	int flag;//标记,是否已经加入到哈夫曼树中
	int parent;//双亲节点下标
	int leftChild;//左孩子下标
	int rightChile;//右孩子下标
}HaffNode;//哈夫曼树的结点构体

typedef struct{

	int bit[MaxN];//数组
	int start;//编码的起始下标
	int weight;//字符的权值
}Code;//哈夫曼编码的结构

//建立哈夫曼树
void Haffman(int weight[],int n,HaffNode haffTree[]){
//建立叶结点个数为n,权值数组为weight的哈夫曼树haffTree
	int i,j,m1,m2,x1,x2;
	//哈夫曼树的haffTree的初始化,n个叶节点的二叉树共有2n-1个结点
	for(i=0;i<2*n-1;i++){

		if(i<n){

			haffTree[i].weight=weight[i];
		}else{

			haffTree[i].weight=0;
		}

		haffTree[i].parent=-1;
		haffTree[i].flag=0;
		haffTree[i].leftChild=-1;
		haffTree[i].rightChile=-1;

	}

	//构造哈夫曼树haffTree的n-1个非叶节点
	for(i=0;i<n-1;i++){

		m1=m2=MaxValue;
		x1=x2;
		for(j=0;j<n+i;j++){//找出权值最小和次小的子树
			if(haffTree[j].weight<m1&&haffTree[j].flag==0){
			//x1最小的下标,x2次小的下标,m1最小的权值,m2次小的权值
				//flag==0表示还没有加入到哈夫曼树
				m2=m1;
				x2=x1;
				m1=haffTree[j].weight;
				x1=j;
			}else if(haffTree[j].weight<m2&&haffTree[j].flag==0){

				m2=haffTree[j].weight;
				x2=j;
			}
		}
		//将找出的两棵权值最小和次小的子树合并为一棵
		haffTree[x1].parent=n+i;
        haffTree[x2].parent=n+i;
		haffTree[x1].flag=1;
		haffTree[x2].flag=1;
		haffTree[n+i].weight=haffTree[x1].weight+haffTree[x2].weight;
		haffTree[n+i].leftChild=x1;
		haffTree[n+i].rightChile=x2;
	}
}

void HaffmanCode(HaffNode haffTree[],int n,Code haffCode[]){

	//由n个结点的哈夫曼树haffTree构造哈夫曼编码haffCode
	Code *cd=(Code *)malloc(sizeof(Code));
	int i,j,child,parent;
	//求n个叶结点的哈夫曼编码
	for(i=0;i<n;i++){
		cd->start=n-1;//不等长编码的最后一位为n-1
		cd->weight=haffTree[i].weight;//取得编码对应的权值
		child=i;
		parent=haffTree[child].parent;
		//由叶节点向上直到根结点
        while(parent!=-1){
			if(haffTree[parent].leftChild==child){

				cd->bit[cd->start]=0;//左孩子分支编码0
			}else{

				cd->bit[cd->start]=1;//右孩子分支编码1
			}
			cd->start--;
			child=parent;
			parent=haffTree[child].parent;
		}
		for(j=cd->start+1;j<n;j++){

			haffCode[i].bit[j]=cd->bit[j];//保存每个叶节点的编码
		}
		haffCode[i].start=cd->start+1;//保存叶结点编码的起始位
		haffCode[i].weight=cd->weight;//保存编码对应的权值
	}
}

void main(){

	int i,j,n=4;
	int weight[]={1,3,5,7};
	HaffNode *myHaffTree=(HaffNode *)malloc(sizeof(HaffNode)*(2*n-1));
	Code *myHaffCode=(Code *)malloc(sizeof(Code)*n);
	if(n>MaxN){

		printf("给出的n越界,修改MaxN!!!\n");
		exit(1);
	}

	Haffman(weight,n,myHaffTree);
	HaffmanCode(myHaffTree,n,myHaffCode);
	//输出每个叶节点的哈夫曼编码
	for(i=0;i<n;i++){

		printf("Weight=%d  Code=",myHaffCode[i].weight);
		for(j=myHaffCode[i].start;j<n;j++){

			printf("%d",myHaffCode[i].bit[j]);
		}
		printf("\n");
	}

}

时间: 2024-10-21 00:14:10

haffman哈夫曼编码的实现的相关文章

java 哈夫曼编码

//哈夫曼树类 public class HaffmanTree { //最大权值 static final int MAXVALUE=1000; int nodeNum ; //叶子结点个数 public HaffmanTree(int n) { this.nodeNum = n; } //构造哈夫曼树算法 public void haffman(int[] weight,HaffNode[] nodes)//权值数组,所有节点数组 { int n = this.nodeNum; //m1,m

哈夫曼(huffman)树和哈夫曼编码

哈夫曼树 哈夫曼树也叫最优二叉树(哈夫曼树) 问题:什么是哈夫曼树? 例:将学生的百分制成绩转换为五分制成绩:≥90 分: A,80-89分: B,70-79分: C,60-69分: D,<60分: E. if (a < 60){ b = 'E'; } else if (a < 70) { b = ‘D’; } else if (a<80) { b = ‘C’; } else if (a<90){ b = ‘B’; } else { b = ‘A’; } 判别树:用于描述分类

(转)哈夫曼(huffman)树和哈夫曼编码

原文地址 哈夫曼树也叫最优二叉树(哈夫曼树) 问题:什么是哈夫曼树? 例:将学生的百分制成绩转换为五分制成绩:≥90 分: A,80-89分: B,70-79分: C,60-69分: D,<60分: E. if (a < 60){ b = 'E'; } else if (a < 70) { b = ‘D’; } else if (a<80) { b = ‘C’; } else if (a<90){ b = ‘B’; } else { b = ‘A’; } 判别树:用于描述分类

基于python的二元霍夫曼编码译码详细设计

一.设计题目 对一幅BMP格式的灰度图像(个人证件照片)进行二元霍夫曼编码和译码 二.算法设计 (1)二元霍夫曼编码: ①:图像灰度处理: 利用python的PIL自带的灰度图像转换函数,首先将彩色图片转为灰度的bmp图像,此时每个像素点可以用单个像素点来表示. ②:二元霍夫曼编码: 程序流程图: 详细设计: 统计像素点频率,首先通过python自带的PIL库的图像像素点读取函数read()获取灰度图像的所有像素点,通过循环遍历每个像素点,将每个出现的像素点值以及其次数以键值对的形式放入到pyt

霍夫曼编码求节省空间

霍夫曼编码将频繁出现的字符采用短编码,出现频率较低的字符采用长编码.具体的操作过程为:i)以每个字符的出现频率作为关键字构建最小优先级队列:ii)取出关键字最小的两个结点生成子树,根节点的关键字为孩子节点关键字之和,并将根节点插入到最小优先级队列中,直至得到一棵最优编码树. 霍夫曼编码方案是基于______策略的.用该方案对包含a到f6个字符的文件进行编码,文件包含100000个字符,每个字符的出现频率(用百分比表示)如表1-3所示,则与固定长度编码相比,该编码方案节省了______存储空间.

哈夫曼树与哈夫曼编码

哈夫曼树与哈夫曼编码 术语: i)路径和路径长度 在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径. 路径中分支的数目称为路径长度.若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1. ii)结点的权及带权路径长度 若对树中的每个结点赋给一个有着某种含义的数值,则这个数值称为该结点的权. 结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积. iii)树的带权路径长度 树的带权路径长度:所有叶子结点的带权路径长度之和,记为WPL. 先了解一下

《数据结构复习笔记》--哈夫曼树,哈夫曼编码

先来了解一下哈夫曼树. 带权路径长度(WPL):设二叉树有n个叶子结点,每个叶子结点带有权值 wk,从根结点到每个叶子结点的长度为 lk,则每个叶子结点的带权路径长度之和就是: 最优二叉树或哈夫曼树: WPL最小的二叉树. [例]有五个叶子结点,它们的权值为{1,2,3,4,5},用此权值序列可以构造出形状不同的多个二叉树. 其中结果wpl最小值的是:33=(1+2)*3+(3)*2+(4+5)*2: 哈夫曼树的构造: 每次把权值最小的两棵二叉树合并, 代码: typedef struct Tr

C语言之霍夫曼编码学习

?1,霍夫曼编码描述哈夫曼树─即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩. 在计算机信息处理中,"哈夫曼编码"是一种一致性编码法(又称"熵编码法"),用于数据的无损耗压缩.这一术语是指使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码.这张编码表的特殊之处在于,它是根据每一个源字符出现的估算概率而建立起来的(出现概率高的字符使用较短的编码,反之出现概率低的则使用较长的编码,这便使编码之后的字符串的平均期望长度降低,从而达到无损压缩数据的目

数据结构课程设计-哈夫曼编码译码

//******************************************** //程序功能:哈夫曼编码及译码 // //日期:2014年11月18 // //******************************************** #include<stdio.h> #include<stdlib.h> #include<string.h> #include <windows.h> #define MAX 128 //叶子节点