最近在学习Huffman树和Huffman编码,最近学习效率下降严重,两天才看懂写出来。
在写本程序的时候,甚至犯了很多低级错误,例如重复包含了头文件……
思路:
1、创建哈夫曼树需要的最小堆;
2、若给与n个带权值节点需要组成哈夫曼树,那么最小堆需要的节点数为2*n-1;
3、将所有给予权值存放入新建节点并插入最小堆;
4、创建哈夫曼树,每次取出两个最小权值节点;创建一个新节点,权值为两节点权值之和,左右儿子为两节点;
5、再将这个新节点插入最小堆中;
6、重复4、5两步骤n-1次,得到哈夫曼树。
具体代码实现如下:
最小堆.h文件:
typedef struct HuffmanTreeNode {
int weight;
struct HuffmanTreeNode* Left;
struct HuffmanTreeNode* Right;
}HTNode;
class MinHeap {
public:
//有参构造函数,参数为堆容量
MinHeap(int max);
//析构函数
~MinHeap();
//1、判断是否为空
bool IsEmpty();
//2、判断是否已满
bool IsFull();
//3、插入元素
bool Insert(HTNode* x);
//4、删除最小元素
HTNode* DeleteMin();
//打印测试
void PrintHeap();
private:
int HeapSize; //堆的大小
HTNode** Heap; //创建堆数组
int HeapCapacity; //堆容量
HTNode* MinData;//0位置填充值,也用来删除提醒是否成功
};
最小堆.cpp文件:
MinHeap::MinHeap(int max) {
//创建0位置填充值
this->MinData = new HTNode();
this->MinData->weight = -1000;
this->MinData->Right = this->MinData->Right = NULL;
this->HeapCapacity = max;
this->Heap = new HTNode*[this->HeapCapacity + 1];
this->HeapSize = 0;
this->Heap[0] = this->MinData;
}
//析构函数
MinHeap::~MinHeap() {
delete[] Heap;
}
//1、判断是否为空
bool MinHeap::IsEmpty() {
if (this->HeapSize == 0) return true;
return false;
}
//2、判断是否已满
bool MinHeap::IsFull() {
if (this->HeapSize == this->HeapCapacity) return true;
return false;
}
//3、插入元素
bool MinHeap::Insert(HTNode* x) {
if (IsFull()) return false;
//定义循环变量i,参与上滤,找到合适位置
int i = ++this->HeapSize;
//如果位置不合适,就把父节点元素换下来,直到找到合适位置i
for (; x->weight < this->Heap[i / 2]->weight; i = i / 2) {
this->Heap[i] = this->Heap[i / 2];
}
this->Heap[i] = x;
return true;
}
//4、删除最小元素
HTNode* MinHeap::DeleteMin() {
if (IsEmpty()) return this->MinData;
HTNode* min = this->Heap[1];
//将最后一个元素拿到,再将堆大小减一,逻辑删除
HTNode* temp = this->Heap[this->HeapSize--];
int i = 1;
int child;
for (; i <= this->HeapSize / 2; i = child) {
//先找到左子节点
child = 2 * i;
//找到两个子节点中最小的
if (child != this->HeapSize && this->Heap[i * 2]->weight > this->Heap[i * 2 + 1]->weight)
child++;
if (temp->weight > this->Heap[child]->weight)
this->Heap[i] = this->Heap[child];
else break;
}
//找到合适位置,赋值
this->Heap[i] = temp;
return min;
}
//打印测试
void MinHeap::PrintHeap() {
for (int i = 1; i <= this->HeapSize; i++) {
cout << this->Heap[i]->weight << " ";
}
cout << endl;
}
Huffman树.h文件:
class HuffmanTree {
public:
//构造函数,参数权值数组和数组元素个数
HuffmanTree(int w[], int n);
//获取根节点
HTNode* GetRoot();
private:
HTNode* Root;
};
Huffman树.cpp文件:
//构造函数,参数权值数组和数组元素个数
HuffmanTree::HuffmanTree(int w[], int n) {
//创建最小堆
MinHeap mh(2 * n - 1);
for (int i = 0; i < n; i++){
HTNode* temp = new HTNode();
temp->weight = w[i];
temp->Right = temp->Left = NULL;
mh.Insert(temp);
}
//建Huffman树
for (int i = 0; i < n - 1; i++) {
HTNode* node1 = mh.DeleteMin();
HTNode* node2 = mh.DeleteMin();
HTNode* newNode = new HTNode();
newNode->weight = node1->weight + node2->weight;
newNode->Left = node1; newNode->Right = node2;
mh.Insert(newNode);
}
this->Root = mh.DeleteMin();
}
//获取根节点
HTNode* HuffmanTree::GetRoot() {
return this->Root;
}
测试代码:
int main() {
int w[] = { 1,2,3,4,5 };
HuffmanTree ht(w, 5);
return 0;
}
调试可看出结果与下图一致。