c语言构造哈夫曼树-哈夫曼编码

构造哈夫曼树
首先,我们需要了解哈夫曼树是什么:

一.相关知识点
路径: 路径是指从一个节点到另一个节点的分支序列。
在这里插入图片描述
路径长度: 指从一个节点到另一个结点所经过的分支数目。 ,从根节点到a的分支数目是2,
在这里插入图片描述
数的路径长度: 树中所有结点的路径长度之和为树的路径长度PL 如图pl为10
在这里插入图片描述
节点的权: 给树的每个结点赋予一个具有某种实际意义的实数,我们称该实数为这个结点的权
在这里插入图片描述
带权路径长度: 从树根到某一结点的路径长度与该节点的权的乘积,叫做该结点的带权路径长度
树的带权路径长度: 树的带权路径长度为树中所有叶子节点的带权路径长度之和。

路径长度为0,最多有一个(根)
路径长度为1,最多有2个(两个孩子)
路径长度为2,最多有4个叶结点。

构造Huffman树的步骤:
1) 根据给定的n个权值,构造n棵只有一个根结点的二叉树,n个权值分别是这些二叉树根结点的权;
2) 设F是由这n棵二叉树构成的集合,在F中选取两棵根结点权值最小的树作为左、右子树,构造成一颗新的二叉树,置新二叉树根结点的权值等于左、右子树根结点的权值之和。为了使得到的哈夫曼树的结构唯一,规定根结点权值最小的作为新二叉树的左子树。
3) 从F中删除这两棵树,并将新树加入F;
4) 重复2)、3)步,直到F中只含一棵树为止,这棵树便是Huffman树。
说明:n个结点需要进行n-1次合并,每次合并都产生一个新的结点,最终的Huffman树共有2n-1个结点。
如何构建哈夫曼树:在网上找了个比较好用的图片:
在这里插入图片描述
如上即可较为清晰的理解最优二叉树的构造了。
三.哈夫曼树代码的实现。

我们给出5个值为:2   3   5   7   8的权值,构造最优二叉树。
从上图可以看出:我们有权值:weight,左右孩子:LChild,RChild,双亲结点:parent,

所以:我们构成了一个哈夫曼树的结点结构HTNode:

Typedef struct
	{
		Int weight;
		Int parent , LChild,RChild;
}HTNode, *HuffmanTree;

void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n){//根据输入的结点的权值和个数来构建赫夫曼树 
	int m=2*n-1;//n个叶子,有2*n-1个结点 
	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++){循环次数为n-1次,进行构造哈夫曼树。
	select(ht,i-1,&s1,&s2);
	/*选择parent为0且weight最小的两个结点,其序号分别赋值给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=(haffmancode)malloc(n*sizeof(char*));申请一个字符给指针,字符的区域hc
给hc分配n个字符编码的头指针	
/*分配n个字符编码的头指针*/ 
	cd=(char*)malloc(n*sizeof(char));cd为中间辅助单元,n个结点的位置为cd
	cd[n-1]='\0';cd的最后一位为编码结束符, 
	for(j=0;j<n;j++){n次循环,
	start=n-1;
	for(c=j;f=ht[j].parent;f!=0;c=f,f=ht[f].parent)
		/*从叶子到根结点求编码*/
		if(ht[f].Lchild==c) cd[--start]='0';
		else cd[--start]='1';
		hc[j]=(char*)malloc((n-start)*sizeof(char));
		/*为第j个指令编码分配空间*/
		strcpy(hc[j],&cd[start]);

下面给出具体实现代码:

#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
#define MAX_NUM 100//最大数字个数为100
#define inf 2000000000 //最大值为
using namespace std;
typedef struct {
	unsigned int weight;//权值 
	unsigned int parent,lchild,rchild;//父节点,孩子结点的权值 
}HTNode,*HuffmanTree;
typedef char * * HuffmanCode;//二维字符数组 
int s1,s2;//最小的两个结点 









void Select(HuffmanTree &HT,int x){//选出无父结点,并且权值最小的两个结点,赋值给s1,s2 
	int i,min1=inf,min2=inf;
	for(i=1;i<=x;i++){//找最小 
		if(HT[i].weight<min1&&HT[i].parent==0){min1=HT[i].weight;s1=i;}
	}
	for(i=1;i<=x;i++){//找次小 
		if(HT[i].weight<min2&&i!=s1&&HT[i].parent==0){
			min2=HT[i].weight;s2=i;
		}
	}
}










void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n){//根据输入的结点的权值和个数来构建赫夫曼树 //创建数 和编码的地址
	if(n<=1)return;
	int m=2*n-1;//n个叶子,有2*n-1个结点 
	int i;
	HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//0号单元未用 开辟空间
	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++){
		Select(HT,i-1);//选出最小的两个无父节点的结点 
		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 *));//申请一段以HC为首地址的内存,可以看成二维字符数组 ,这里先申请了第一维 
	char *cd=(char *)malloc(n*sizeof(char));//申请一段临时工作空间 
	cd[n-1]='\0';//编码结束符 
	for(i=1;i<=n;i++){
		int start=n-1,c,f;
		for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent){//从叶子到根逆向求编码 
			if(HT[f].lchild==c)cd[--start]='0';//如果当前结点是父节点的左孩子,则存一个1 
			else cd[--start]='1';//反之 
		}
		HC[i]=(char *)malloc((n-start)*sizeof(char));//申请第二维 
		strcpy(HC[i],&cd[start]);//将编码从工作空间存入赫夫曼编码表中 
	}
	free(cd); //释放临时空间 
}









int main(){
	HuffmanTree HT;//自定义结构体  ht
	HuffmanCode HC;
	int w[MAX_NUM],n;
	int i;
	printf("输入结点的个数:\n"); 
	scanf("%d",&n);
	printf("输入每个结点的权值:\n");
	for( i=0;i<n;i++)
	scanf("%d",&w[i]);
	HuffmanCoding(HT,HC,w,n);
	for( i=1;i<=n;i++)
	printf("%d的赫夫曼编码为:%s\n",HT[i].weight,HC[i]);
	return 0;
} 

因为刚好学到这里,便做了个总结。

  • 58
    点赞
  • 272
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
以下是使用C语言构造哈夫曼树并打印哈夫曼编码的示例代码: ```c #include <stdio.h> #include <stdlib.h> typedef struct HuffmanNode { int weight; struct HuffmanNode *left; struct HuffmanNode *right; } HuffmanNode; typedef struct { int size; HuffmanNode **nodes; } MinHeap; HuffmanNode* createHuffmanNode(int weight) { HuffmanNode *node = (HuffmanNode*)malloc(sizeof(HuffmanNode)); node->weight = weight; node->left = NULL; node->right = NULL; return node; } MinHeap* createMinHeap(int capacity) { MinHeap *heap = (MinHeap*)malloc(sizeof(MinHeap)); heap->size = 0; heap->nodes = (HuffmanNode**)malloc(capacity * sizeof(HuffmanNode*)); return heap; } void swapNodes(HuffmanNode **a, HuffmanNode **b) { HuffmanNode *temp = *a; *a = *b; *b = temp; } void minHeapify(MinHeap *heap, int idx) { int smallest = idx; int left = 2 * idx + 1; int right = 2 * idx + 2; if (left < heap->size && heap->nodes[left]->weight < heap->nodes[smallest]->weight) { smallest = left; } if (right < heap->size && heap->nodes[right]->weight < heap->nodes[smallest]->weight) { smallest = right; } if (smallest != idx) { swapNodes(&heap->nodes[idx], &heap->nodes[smallest]); minHeapify(heap, smallest); } } void buildMinHeap(MinHeap *heap) { int n = heap->size - 1; int i; for (i = (n - 1) / 2; i >= 0; i--) { minHeapify(heap, i); } } HuffmanNode* extractMin(MinHeap *heap) { HuffmanNode *minNode = heap->nodes[0]; heap->nodes[0] = heap->nodes[heap->size - 1]; heap->size--; minHeapify(heap, 0); return minNode; } void insertMinHeap(MinHeap *heap, HuffmanNode *node) { int i = heap->size; heap->size++; while (i > 0 && node->weight < heap->nodes[(i - 1) / 2]->weight) { heap->nodes[i] = heap->nodes[(i - 1) / 2]; i = (i - 1) / 2; } heap->nodes[i] = node; } int isLeaf(HuffmanNode *node) { return !(node->left) && !(node->right); } void printCodes(HuffmanNode *root, int *code, int top) { if (root->left) { code[top] = 0; printCodes(root->left, code, top + 1); } if (root->right) { code[top] = 1; printCodes(root->right, code, top + 1); } if (isLeaf(root)) { printf("Character: %c, Weight: %d, Code: ", root->data, root->weight); for (int i = 0; i < top; i++) { printf("%d", code[i]); } printf("\n"); } } void huffmanCoding(int *weights, int num) { MinHeap *heap = createMinHeap(num); for (int i = 0; i < num; i++) { heap->nodes[i] = createHuffmanNode(weights[i]); } heap->size = num; buildMinHeap(heap); while (heap->size > 1) { HuffmanNode *left = extractMin(heap); HuffmanNode *right = extractMin(heap); HuffmanNode *newNode = createHuffmanNode(left->weight + right->weight); newNode->left = left; newNode->right = right; insertMinHeap(heap, newNode); } int code[100]; int top = 0; HuffmanNode *root = extractMin(heap); printCodes(root, code, top); } int main() { int weights[] = {5, 9, 12, 13, 16, 45}; int num = sizeof(weights) / sizeof(weights[0]); huffmanCoding(weights, num); return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值