Huffman编码的c语言实现

让人想犯罪 __ 提交于 2020-02-05 20:14:47
 在此本人用一个简单的例子来介绍Huffmantree。

a ,b,c,d,e频率分别为2、4、1、5、3,首先来建立Huffmantree.a、b、c、d、e分别代表此Hufmantree的5个叶子节点,刚开始时这5个节点代表5棵树,这5棵树组成森林。取森林中频率最小的两棵树,合成一棵二叉树,该二叉树的根节点的频率为这两个叶子结点的频率之和,将这两个频率最小的树从森林中删掉,新的树加入森林,一次重复此步骤,知道建立一棵Huffmantree.
以此例为例子,建立Huffamtree的各个步骤如下:
在这里插入图片描述
最后建立的Huffmantree如下:
在这里插入图片描述
在Huffmantree中,结点的左边为编码‘0’,右边为编码‘1’,故在该Huffmantree中,a的编码为001,b的编码为10,c的编码为000,d的编码为11,e的编码为01。
下面用c语言来实现Huffman编码:
程序的主要思路如下:
首先定义一个结构体数组,结构体的成员有:数据内容,频率,节点的父母亲,节点的右、左儿子。Huffmantree有5个叶子节点,故Huffmantree共有25-1个节点,所以结构体数组的的长度可为25(序号为0的节点未使用)。1~5号节点为叶子节点,其余的节点为Huffmantree的内部节点,根据Huffmantree的建立规则,建立对应的Huffmantree,然后根据Huffmantree求出对应的叶子节点的Huffman编码。
具体代码代码如下

#include <iostream>
#include<stdlib.h>
#include<string.h>
typedef struct {
	int weight;
	int parent;
	int lchild;
	int rchild;
}HTNode,*HTree;
typedef char** Huffmancode;
int Min(HTree HT, int n) {  //选择最小的节点
	int i=0;
	while (HT[i].parent!= 0)//选出HT中第一个节点的parent不为0的节点
		i++;
	int min_weight = HT[i].weight;
	int min = i;
	for (; i < n; i++) {
		if (min_weight >=HT[i].weight&&HT[i].parent==0) {
			min_weight = HT[i].weight;
			min = i;
		}
		else
			continue;
	}
	HT[min].parent = 1;// 避免进行第二次进行选择时再次选到同一个最小节点
	return min;
}
void Select_min(HTree HT, int k, int& m1, int& m2) {  //选出最小节点及次小的节点
	m1 = Min(HT, k);
	m2 = Min(HT, k);
}
HTree Creating_Huffmantree(int* w, int n) {//构造Huffmantree
	HTree HT = (HTNode*)malloc(2 * n * sizeof(HTNode));
	if (HT == NULL) {
		printf("内存分配不成功!\n");
		exit(1);
	}
	else {
		int i = 1;//Huffmantree数组的下标从1开始
		for (; i <= n; i++) {//初始化Huffmantree
			HT[i].weight = *w;
			w++;
			HT[i].parent = 0;
			HT[i].lchild = 0;
			HT[i].rchild = 0;
		}
		for (; i < 2 * n; i++) {
			HT[i].weight = 0;
			HT[i].parent = 0;
			HT[i].lchild = 0;
			HT[i].rchild = 0;
		}
	}
	int min1, min2;//用于存放最小的两个节点的序号
	for (int j = n + 1; j < 2 * n; j++) {
		Select_min(HT, j, min1, min2);
		HT[min1].parent = j;
		HT[j].lchild = min1;
		HT[min2].parent = j;
		HT[j].rchild = min2;
		HT[j].weight = HT[min1].weight + HT[min2].weight;
	}
	return HT;
}
int Depth(HTree HT,int index) {//返回叶子结点的深度
	int temp=index;
	int Dcount = 0;
	while (HT[temp].parent != 0) {//求序号为i的叶子节点的路径长
		temp = HT[temp].parent;
		Dcount++;
	}
	return Dcount;
}
int WPL(HTree HT,int n) {//从叶子节点开始求Huffmantree的带权路径长度
	int tatal_weight = 0;
	for (int i = 1; i <= n; i++) {
		
		tatal_weight += HT[i].weight * Depth(HT, i);
	}
	return tatal_weight;
}
void Huffmancoding(HTree HT,Huffmancode  HC, int n) {//为Huffmantree 编码
	HC = (char**)malloc(n * sizeof(char*));
	if (HC == NULL) {
		printf("内存分配不成功!\n");
		exit(1);
	}
	else {
		for (int i = 1; i <= n; i++) {
			int H = Depth(HT, i);
			char* s = (char*)malloc((H + 1) * sizeof(char));//用于存储序号为i的叶子节点的逆序编码
			if (s == NULL) {
				printf("内存分配不成功!\n");
				exit(1);
			}
			else {
				int t1 = i;
				int t2 = HT[t1].parent;
				for (int j = 0; j < H; j++) {

					if (t1 == HT[t2].lchild)
						s[H-j-1] = '0';
					else if (t1 == HT[t2].rchild)
						s[H-j-1] = '1';
					else {
						printf("编码错误!\n");
						exit(1);
					}
					t1 = t2;
					t2 = HT[t2].parent;
				}
				s[H] = '\0';
				
				HC[i] = (char*)malloc((H + 1) * sizeof(char));
				if (HC[i] == NULL) {
					printf("内存分配不成功!\n");
					exit(1);
				}
				else
				    strcpy_s(HC[i],H+1, s);
				printf("%s\n", HC[i]);
				free(s);
			}
			
		}
		
	}
	
}


int main() {
	int w[5] = { 2,4,1,5,3 };//以此为a,b,c,d,e的频率
	int n = 5;
	HTree T = NULL;
	 T = Creating_Huffmantree(w,n);
	 for (int i = 1; i < 2 * n; i++) {
		 printf("%d\n", i);
		 printf("weight=%d\n", T[i].weight);
		 printf("parent=%d\n", T[i].parent);
		 printf("lchild=%d\n", T[i].lchild);
		 printf("rchild=%d\n", T[i].rchild);
		
	 }
	 printf("Huffmantree总的带权路径长度为:%d\n", WPL(T, n));
	 Huffmancode HC=NULL;
	 printf("叶子结点a,b,c,d,e的Huffman编码依次如下:\n");
	 Huffmancoding(T, HC, n);
	return 0;
}






运行结果如下:
在这里插入图片描述
在这里插入图片描述

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!