哈夫曼编码的简单实例

最近有被要求写一个哈夫曼的编码和解码的程序。简单的是一个实例就行了,那我就动手写了。刚开始还真的挺困难,虽然原理懂,但是捣鼓了好久还是得依靠网上的资源编写出了带有图形界面的简单哈夫曼编码实例。


构建哈夫曼编码思路:

1、构建哈夫曼编码树,需要知道一共有多少个元素需要编码,这里给出a-e五个字母,然后开始构建哈夫曼树;

2、方法:首先,随机抽取5个字母,这里一共抽取了1-30次,统计每个字母出现的次数,作为权重;然后,找出权重最小的两个字母组建树,作为两个子节点,把权重加起来,作为父节点;接着,继续寻找两个最小权重的,进行组合;最后,把所有元素组合起来,作为一棵新的树;

3、组建好树以后,开始对树的节点进行编码。从叶子开始编码,左子树为0,右子树为1,然后判断是父节点是在左边还是在右边,直到判断到根部结束编码,对全部子叶编码后得出编码数组;

4、取出编码数组,对应a-e这几个字母;

5、对随机抽取的0-30个字母,进行一个一个编码,编码按照编码数组的编码表编码;

6、最后是解码,解码就是用已经编好的编码组进行解码。方法:对编码数组中元素逐个对照树编码表解码,例如:编码数组: 11011,对A的编码是110,从树的根部开始搜索 1 1 0后,判断没有儿子结束,判断为树的A的位置,返回A。如此类推,进行解码。


部分代码分析:

	typedef struct{  
		unsigned int weight;  
		unsigned int parent, lchild, rchild;  
	}HTNode, *HuffmanTree;      //动态分配数组存储哈夫曼树  

	typedef char* HuffmanCode;   //动态分配数组存储哈夫曼编码表 
新建哈夫曼树结构体,权重,父节点,左儿子,右儿子


	//选出weight最小的两个结点,s1保存最小的,s2保存第二小的  
	void SelectMin(HuffmanTree HT, int nNode)  
	{  
		int i, j;  
		for(i = 1; i <= nNode; i++)  
			if(!HT[i].parent)  
			{  
				s1 = i;  //s1 ,s2为int型,用作保存编号
				break;  
			}  
			for(j = i+1; j <= nNode; j++)  
				if(!HT[j].parent)  
				{  
					s2 = j;  
					break;  
				}  

				for(i = 1; i <= nNode; i++)  
					if((HT[i].weight < HT[s1].weight) && (!HT[i].parent) && (s2 != i))  
						s1 = i;  
				for(j = 1; j <= nNode; j++)  
					if((HT[j].weight < HT[s2].weight) && (!HT[j].parent) && (s1 != j))  
						s2 = j;  
				// 以上只筛选出最小的两个,这里保证s1的weight比s2的小  
				if(HT[s1].weight > HT[s2].weight)  
				{  
					int tmp = s1;  
					s1 = s2;  
					s2 = tmp;  
				}  
	}  


	// w[]存放nNode个字符的权值(均大于0),构造哈夫曼树HT,  
	// 并求出nNode个字符的哈夫曼编码HC  
	void HuffmanCoding(HuffmanTree &HT, HuffmanCode *&HC, int *w, int nNode)  
	{  
		int i;
		char *hfcode;  
		int p;    
		if(nNode < 1)  
			return;  
		m = 2*nNode-1;   //哈夫曼树的结点数,定理公式  

		/////////////////////////////以下是求Huffman树的初始化/////////////////////////////  
		HT = (HTNode*) malloc ((m+1) *sizeof(HTNode));  //0号单元未用  
		for(i = 1; i <= nNode; i++)    //初始化  
		{  
			HT[i].weight = w[i-1];  
			HT[i].parent = 0;  
			HT[i].lchild = 0;  
			HT[i].rchild = 0;  
		}  
		for(i = nNode+1; i <= m; i++)  
		{  
			HT[i].weight = 0;  
			HT[i].parent = 0;  
			HT[i].lchild = 0;  
			HT[i].rchild = 0;  
		}  

		/////////////////////////////以下是Huffman树的构建/////////////////////////////  
		for(i = nNode+1; i <= m; i++)  
		{  
			// 建立哈夫曼树  
			// 在HT[1..i-1]中选择parent为0且weight最小的两个节点  
			// 其序号分别是s1和s2,并且小的是左孩子   
			SelectMin(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;  
		}  


		/////////////////////////////以下是求Huffman树的编码/////////////////////////////  

		/*该方法是从每个叶结点开始上溯,以从后向前的方式生成huffman编码*/   
		hfcode = (char *) malloc ( (nNode + 1) * sizeof( char ) );  
		hfcode[nNode] = '\0';   //编码以‘\0’结尾  
		int start;  
		int c;   //c:当前处理节点,p是c的父结点  
		for(int i=1; i<=nNode; i++)   
		{  
			start = nNode;  
			for(c=i, p=HT[c].parent; p!=0; c=p,p=HT[p].parent)  
			{  
				if(c==HT[p].lchild)  
					hfcode[--start]='0';  
				else if(c==HT[p].rchild)  
					hfcode[--start]='1';  
			}  
			//申请足够存放该节点编码就行,不浪费;  
			HC[i] = (char *) malloc ((nNode-start+1) * sizeof(char));    
			strcpy(HC[i], &hfcode[start]);  
		}  
		free(hfcode);   

	} 

	/*Huffman解码函数 
	*HT:Huffman树,w[]:权值数组(从下标0开始),code[]:要解码的串 
	*/   
	void HuffmanDecode(HuffmanTree HT, int w[], char code[])  
	{  
		char *ch = code;
		int i,k; 
		k = 0;
		while( *ch != '\0' ){  
			//解码一个结点每次都从树根m开始  
			for(i=m; HT[i].lchild !=0 && HT[i].rchild != 0; ){  
				if( *ch == '0' )  
					i = HT[i].lchild;  
				else if( *ch == '1' )  
					i = HT[i].rchild;  
				++ch;  
			}  
			hDecode[k] = i-1;
			k++;
		}  
	}  

完整工程文件见我的下载资源:

http://download.csdn.net/detail/typersever/9153119

欢迎交流,学习

你可能感兴趣的:(C++,算法)