Huffman树的C++实现与利用Huffman树实现简单压缩功能和解压压缩功能

本文介绍了如何使用C++实现Huffman树,并利用Huffman树进行文件压缩和解压。文章详细阐述了构建Huffman树的过程,包括统计字符频率、建立最小堆和合并节点。此外,还讲解了压缩文件的存储方式以及解压时如何还原Huffman树和解码。主要代码分布在Compress.h和Uncompress.h头文件中,以及main.cpp的主函数部分。
摘要由CSDN通过智能技术生成

Huffman树的C++实现

Huffman树的C++实现与利用Huffman树实现简单压缩功能和解压功能

 最近学习数据结构,用C++写了一个Huffman树,并利用Huffman树实现了简单的文件压缩功能。代码写得不咋好,很多地方显得比较冗余,都可以继续优化,但是最近临近期末也没时间搞这些了,准备寒假再好好弄一弄。也算是自己写的第一篇博客,有出错或者不对的地方还望各位大佬斧正。(/逃)
 Huffman树是一种常见的数据结构类型,常用与图片、文本等文件的压缩。Huffman树的具体原理在利用对每一个字符统计其在文本中出现的频率,将其建立为一个一个单独的树,然后利用堆将这些树合并,得到一颗Huffman树。
 首先构建Huffman树需要建立一个TreeNode结点用于存储文本的数据、出现的频率(即权重)
 然后建立一个堆(利用数组实现),可以用于处理TreeNode结点。
 然后建立一个weights类用于统计和存放文本信息。为统计字符信息的ASCII码值,开辟一个大小为256的weight[256]数组,用数组下标即为字符的ASCII码。如"A"的ASCII码是65,那么A应该被存放咋weight[65]这个对象中。
 接着可以利用写出的堆和weight类以及TreeNode类建立Huffman树。具体实现思路:将对所有在文本中出现的字符,都开辟一个新的TreeNode对象存储其ASCII码与字符权重。然后将所有的TreeNode文本对象放入堆中,接着对堆进行操作。取出堆中前两个元素,将这两个TreeNode对象进行合并生成一个新的TreeNode对象。然后将新的对象插入到堆中去,再重复上述操作。直到堆中只剩下一个元素,就得到了Huffman树。
 具体实现代码如下:
  为实现代码的简洁性,将weights类写入了一个单独的头文件

#ifndef Weights
#define Weights
#include<iostream>
#include<string>
/* weights类用于存储原文件文本信息,包括出现频率(权重)、字符ASCII码、以及字符通过Huffman树生成的对应的编码*/
class weights {
   
public:
	int count = 0;
	char ch;
	std::string code;
	weights(int fre, char it)
	{
   
		count = fre;
		ch = it;
	}
	weights() {
   };
	~weights() {
   };
};
#endif // !Weights

最小堆

#ifndef MinHeap
#define MinHeap
template<typename T>
class heap
{
   
private:
	T   *Heap;
	int max_size;
	int n=0;

	void siftdown(int pos)//siftdown 操作,堆构建的关键
	{
   
		while (!is_leaf(pos)) 
		{
   
			int j = left_child(pos);
			int  rc = right_child(pos);
			if (rc < n&&prior(Heap[rc], Heap[j]))
				j = rc;
			if (prior(Heap[pos], Heap[j]))
				return;
			swap(Heap, pos, j);
			pos = j;
		}
	}

	void siftUp(int start) // 向上调整堆数组
	{
   
		int i = start;
	    int j = (i - 1) / 2;
        T temp = Heap[i];
        while (i>0) 
		{
   
			if (temp->getweight() >= Heap[j]->getweight())
				break;
             Heap[i] = Heap[j];
             i = j;
             j = (i - 1) / 2;
		}
		Heap[i] = temp;
	}

public:
	heap(T *array, int num, int max)//堆的构造函数,传入需要构造堆的数组即可构造一个堆的对象
	{
   
		Heap = array;
		n = num;
		max_size = max;
		bulid_heap();
	}

	heap() {
   };

	bool is_leaf(int pos)//是否为叶节点
	{
   
		if (pos >= n / 2 && pos < n)
			return true;
		else return false;
	}

	int left_child(int pos)//左子节点在数组中的位置
	{
   
		return pos * 2 + 1;
	}

	int right_child(int pos)//右子节点在数组中的位置
	{
   
		return pos * 2 + 2;
	}

	int is_parent(int pos)//父节点在数组中的位置
	{
   
		return (pos - 1) / 2;
	}

	void bulid_heap()//堆构建函数
	{
   
		for (int i = n / 2 - 1; i >= 0; i--)
			siftdown(i);
	}

	bool prior(T array_1, T array_2)//最大堆与最小堆的建堆依据
	{
   
		if (array_1->getweight() < array_2->getweight())
			return true;
		else return false;
	}

	void swap(T *Heap, int i, int j)//交换元素
	{
   
		T temp = Heap[i];
		Heap[i] = Heap[j];
		Heap[j] = temp;
	}

	void print()
	{
   
		for (int i = 0; i < n; i++)
		{
   
			cout << Heap[i] << '\t';
		}
		cout << endl;
	}

	T removefirst()
	{
   
		if (n == 0)
			return NULL;//n为0堆为空返回值-1
		swap(Heap, --n, 0);
		if (n!=0)
				siftdown(0);
		return Heap[n];
	}

	void insert(const T & it) 
	{
   
		if (n == max_size)
		{
   
			cout << "Heap Full" << endl;
			return;
		}
		Heap[n] = it;
		siftUp(n);
		n
综合实验: 1. 问题描述 利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。这要求在发送端通过一个编码系统对待传输数据预先编码,在接收端将传来的数据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的信息收发站编写一个哈夫曼码的编/译码系统。 2. 基本要求 一个完整的系统应具有以下功能: (1) I:初始化(Initialization)。从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。 (2) E:编码(Encoding)。利用已建好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。 (3) D:译码(Decoding)。利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件Textfile中。 (4) P:印代码文件(Print)。将文件CodeFile以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件CodePrin中。 (5) T:印哈夫曼树(Tree printing)。将已在内存中的哈夫曼树以直观的方式(比如)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint 中。 3. 测试数据 用下表给出的字符集和频度的实际统计数据建立哈夫曼树,并实现以下报文的编码和译码:“THIS PROGRAME IS MY FAVORITE”。 字符 A B C D E F G H I J K L M 频度 186 64 13 22 32 103 21 15 47 57 1 5 32 20 字符 N O P Q R S T U V W X Y Z 频度 57 63 15 1 48 51 80 23 8 18 1 16 1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值