C语言——创建哈夫曼树和求解哈夫曼编码

该代码示例展示了如何使用C++构建哈夫曼树并求解哈夫曼编码。程序通过动态分配内存,初始化哈夫曼树节点,输入权值,然后通过多次合并最小权值节点来构造树。最后,从叶子节点到根节点反向计算每个节点的哈夫曼编码。
摘要由CSDN通过智能技术生成

**哈夫曼树:**给定一组具有确定权值的叶子结点,带权路径长度最小的二叉树。

哈夫曼树(n个结点构造哈夫曼树,总共需要2n-1大小的数组存储)
huffTree数组[权值weight、双亲parent、左孩子lchild、右孩子rchild]
1.数组HuffNode初始化,所有元素结点的双亲、左右孩子都置为-1;
2.数组HuffNode的前n个元素的权值置给定值w[n];
3.进行n-1次合并.在二叉树集合中选取两个权值最小的根结点,其下标分别为x1,x2; 将二叉树x1,x2合并为一棵新的二叉树k
(1)赋新权;
(2)x1、x2的双亲结点为k;
(3)更新该结点的左孩子为x1,右孩子为x2;
(4)将i1和i2删去;

*键盘输入n,定义动态数组的方法:int a=new int[n]
代码如下:

#include<iostream>
#include <string.h>
using namespace std;
#define MAXVALUE 2147483647  //最大权值

/*哈夫曼树的数据结构*/
typedef struct{
	int weight; //权值
	int parent; //父节点下标
	int lchild; //左孩子节点的下标
	int rchild; //右孩子节点的下标
} HTNodeType;

//函数声明 
void HuffmanTree(HTNodeType HuffNode[],int n);                     //1 创建哈夫曼树
void HuffmanCode(HTNodeType HuffNode[],char *huffCode[], int n);                        //2 求哈夫曼编码

int main(){	
	int n;//结点个数
	cout<<"输入结点个数:";
	cin>>n;
	HTNodeType *HuffNode=new HTNodeType[2*n-1];//哈夫曼树结点数组
	int *weight=new int[n];//权值数组
	char **huffCode=new char*[n];//指针数组,指向n个哈夫曼编码字符串
	HuffmanTree(HuffNode,n);
	HuffmanCode(HuffNode,huffCode,n);
	cout<<"哈夫曼编码:"<<endl; 
	for(int i=0;i<=n;i++){
		cout<<huffCode[i]<<endl;
	}
	return 0;
}

//创建哈夫曼树
void HuffmanTree(HTNodeType HuffNode[],int n)
{
	int i = 0, j = 0;
	for (i = 0; i < 2 * n - 1; i++){//初始化所有结点的项目为-1 
		HuffNode[i].weight = 0;
		HuffNode[i].parent = -1;
		HuffNode[i].lchild = -1;
		HuffNode[i].rchild = -1;
	}
	cout<<"输入"<<n<<"个权值:";
	for(i=0;i<n;i++){//输入权值 
		cin>>HuffNode[i].weight;
	}
	for (i = 0; i < n - 1; i++){  //找到parent为-1的最小和次小的结点 
		int m1 = MAXVALUE, m2 = MAXVALUE, x1 = -1, x2 = -1;
		for (j = 0; j < n + i; j++){
			if (HuffNode[j].weight < m1 && HuffNode[j].parent == -1){
				m2 = m1;
				x2 = x1;
				m1 = HuffNode[j].weight;
				x1 = j;
			}
			else if (HuffNode[j].weight < m2 && HuffNode[j].parent == -1){
				m2 = HuffNode[j].weight;
				x2 = j;
			}
		}
		//选中x1,x2合并,更新结点 
		HuffNode[n + i].weight = m1 + m2;//新的结点权值为x1和x2的权值之和
		HuffNode[x1].parent = n + i;//x1的双亲结点为新结点 
		HuffNode[x2].parent = n + i;//x2的双亲结点为新结点 
		HuffNode[n + i].lchild = x1;//左孩子为x1 
		HuffNode[n + i].rchild = x2;//右孩子为x1 
	}
}

//从叶子到根逆向求每个字符的哈夫曼编码
void HuffmanCode(HTNodeType HuffNode[], char *huffCode[],int n)
{
	char *temp=new char[n];//定义工作空间,存储临时产生的编码串
	temp[n-1] ='\0';
	int start,pos;
	for (int i = 0; i < n; i++){//遍历哈夫曼树数组,生成哈夫曼编码 
		start=n-1;
		pos=i;//pos记录正在处理的当前位置,也就是孩子结点
		int f=HuffNode[pos].parent;
		while(f!=-1){
			if(HuffNode[f].lchild==pos){ 
				temp[--start]='0';  //是左孩子编码0
			}
			else{
				temp[--start]='1';  //是右孩子编码1
			}
			pos=f;//更新pos结点,移动到它的父亲 
			f=HuffNode[pos].parent;//更新父结点 
		}
		huffCode[i]=new char[n-start];//建立哈夫曼编码实际需要的内存空间
		strcpy(huffCode[i],&temp[start]);//将哈夫曼编码存储到huffCode中 
	}
	delete temp;//释放存储空间 
}

运行结果如下:
在这里插入图片描述
这个代码经过试验,可以完整运行,至于算法的详细讲解,可以去B站看“懒猫老师”的视频哦,视频中的图解可帮助快速理解算法原理。
【懒猫老师-数据结构-(34)哈夫曼树(Huffman Tree,霍夫曼树,赫夫曼树)-哔哩哔哩】
【懒猫老师-数据结构-(35)哈夫曼编码1(Huffman coding,霍夫曼编码,赫夫曼编码)-哔哩哔哩】

//算法5.11 根据赫夫曼树求赫夫曼编码 #include using namespace std; 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;//恢复原来的值 } //用算法5.10构造赫夫曼树 void CreatHuffmanTree(HuffmanTree &HT,int n) { //构造赫夫曼树HT int m,s1,s2,i; if(n<=1) return; m=2*n-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; } cout<<"输入叶子结点权值:\n"; for(i=1;i>HT[i].weight; /*――――――――――初始化工作结束,下面开始创建赫夫曼树――――――――――*/ for(i=n+1;i<=m;++i) { //通过n-1次的选择、删除、合并来创建赫夫曼树 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].lchild=s1; HT[i].rchild=s2 ; //s1,s2分别作为i的左右孩子 HT[i].weight=HT[s1].weight+HT[s2].weight; //i 的权值为左右孩子权值之和 } //for } // CreatHuffmanTree void CreatHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n) { //从叶子到根逆向求每个字符的赫夫曼编码,存储在编码表HC中 int i,start,c,f; HC=new char*[n+1]; //分配n个字符编码的头指针矢量 char *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; //回
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小王不熬夜.com

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值