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)