哈夫曼编码的实现(详细思路及c++一步一步代码实现)

至于哈夫曼树的实现:在我的上一篇博客已经详细的介绍了。

需要的点击传送门。

哈夫曼编码的两个特殊性质:
1、哈夫曼编码是前缀编码。(问:啥是前缀编码? 前缀编码就是在一个编码方案中,任何一个编码度不是其他任何编码的前缀(最左子串),那么这个编码就是前缀编码。
2、哈夫曼编码是最优前缀编码。对于包括n个字符的数据文件,分别以它们的出现次数为权值来构造哈夫曼树,则利用该树对应的哈夫曼编码对文件进行编码,能使该文件压缩后对应的二进制文件的长度最短

哈夫曼编码的算法实现:

1、哈夫曼编码的主要思想: 在构造完哈夫曼树之后,通过这棵哈夫曼树来求得哈夫曼编码:依次以叶子为出发点,向上回溯到根节点位置,回溯的时候如果走的是左分支则生成代码0,如果是有分支则生成代码1。

  • 注意几个点:
  • 1、 通过哈夫曼树构建哈夫曼编码的时候是从叶子节点往回回溯知道根节点得到的。
  • 2、哈夫曼编码是变长编码,因此我们使用一个指针数组来存放每个字符编码串的首地址。

具体代码实现即思路如下:

1、首先是先定义一个用来存储哈夫曼编码的数组,数组的元素类型为HaFuManCode,HaFuManCode定义如下

class HaFuManCode {
	//哈夫曼编码public:
	char ch;//存储字符
	char* hafumanCode;//存储各个字符所对应的哈夫曼编码
};

接着是定义一个存储哈夫曼编码的数组 hafumancode

HaFuManCode* hafumancode = new HaFuManCode[n];

2、然后写构造哈夫曼编码的函数,实现的思路如下:

  • 在哈夫曼树中,先找到叶子节点,然后向上回溯,每一次回溯都查看是双亲节点的左孩子还是右孩子,如果是左孩子,那么编码就是’0’,反之,如果是右孩子,那么编码就是‘1’。将得到的‘1’或者‘0’存储到临时的数组中,直到回溯到根节点为止即结束。
  • 在上述的过程中,我们为什么将得到的编码存储到临时的数组中?由于我们是从根节点向上回溯的,所以得到的哈夫曼编码是倒序的,我们为了方便,先将编码存储到临时的数组中,待回溯到根节点的时候,我们再将编码正序的存到hafumancode数组中即可。

详细代码如下:

void creatHafumanCode(HaFuMan* hafuman, HaFuManCode* hafumancode, int n,char* ch) {

	for (int i = 0; i < n; i++) {
		hafumancode[i].ch = ch[i];//将字符放进去
	}

	char* tempCode = new char[n];//用来临时保存编码的数组

	for (int i = 0; i < n; i++) {
		//有n个叶子,我们就进行n次编码

		int front = hafuman[i].parents;//表示当前节点的双亲位置
		int temp = i;//记录当前节点的位置
		int index = n - 1;
		tempCode[n - 1] = '\0';
		while (front != -1) {//直到找到根节点

			--index;
			if (hafuman[front].lchild == temp) { 
				tempCode[index] = '0';//左孩子为 0
			}
			else {
				tempCode[index] = '1';//右孩子为 1
			}

			//接下来我们判断当前节点的双亲节点(接着回溯),直到根节点的时候停止进行循环
			temp = hafuman[temp].parents;
			front = hafuman[front].parents;
		}

		//将保存在tempcode的编码读取出来(由于我们是倒序存储进去)
		hafumancode[i].hafumanCode = new char[n - index];
		for (int j = 0; j < n-index; j++) {
			hafumancode[i].hafumanCode[j] = tempCode[j + index];//将临时的编码转移到存放哈夫曼编码的数组中
		}//转移成功
	}
}

3、将得到的哈夫曼编码打印出来即可:

void print_hafumancode(HaFuManCode* hafumancode,int n) {
	for (int i = 0; i < n; i++) {
		int j = 0;
		cout << hafumancode[i].ch<<" hafumancode is:";
		while (hafumancode[i].hafumanCode[j]!='\0')
		{
			cout << hafumancode[i].hafumanCode[j] << " ";
			j++;
		}
		cout << endl;
		j = 0;
	}
}

哈夫曼编码的实现(详细思路及c++一步一步代码实现)_第1张图片
main()函数如下:

int main() {

   int n;
   cout << "叶子个数" << endl;
   cin >> n;

   int a[8] = {1,1,2,3,6,3,2,1};
   char ch[8] = { 'A','B','C','D','E','F','G','H' };

   //申请一个长度为2n的哈夫曼结构数组
   HaFuMan* hafuman = new HaFuMan[2*n-1];
   
   creathaFuMan(hafuman, n, a);
   printHaFuMan(hafuman, n);
   HaFuManCode* hafumancode = new HaFuManCode[n];
   creatHafumanCode(hafuman, hafumancode, n,ch);

   print_hafumancode(hafumancode,n);


   system("pause");
   return 0;
}

入坑不久,有错望指正谢谢!

你可能感兴趣的:(C++,数据结构)