霍夫曼编码是一种无损数据压缩算法。其思想是为输入字符分配可变长度代码,分配代码的长度基于相应字符的频率。
代码实现
#include <cstdlib>
#include <iostream>
using namespace std;
#define MAX_TREE_HT 100
struct MinHeapNode {
char data;
//权重
unsigned freq;
struct MinHeapNode *left, *right;
};
struct MinHeap{
//二叉堆大小
unsigned size;
unsigned capacity;
//指向指针的指针方便动态分配 指针数组
struct MinHeapNode** array;
};
struct MinHeapNode* newNode(char data,unsigned freq){
//申请内存
struct MinHeapNode* temp = (struct MinHeapNode*)malloc(
sizeof(struct MinHeapNode));
temp->left = temp->right = NULL;
temp->data = data;
temp->freq = freq;
return temp;
};
//创建最小堆
struct MinHeap* createMinHeap(unsigned capacity) {
//申请内存
struct MinHeap* minheap
= (struct MinHeap*)malloc(sizeof(struct MinHeap));
minheap->size = 0;
minheap->capacity = capacity;
minheap->array = (struct MinHeapNode**)malloc(
minheap->capacity * sizeof(struct MinHeapNode*));
return minheap;
}
//交换节点位置
void swapMinHeapNode(struct MinHeapNode** a,
struct MinHeapNode** b
) {
struct MinHeapNode* t = *a;
*a = *b;
*b = t;
}
//维护最小堆
void minHeapify(struct MinHeap* minheap, int idx)
{
int smallest = idx;
int left = 2 * idx + 1;//左子节点
int right = 2 * idx + 2;//右子节点
//查看左节点权重是否更小
if (left < minheap->size
&& minheap->array[left]->freq
< minheap->array[smallest]->freq)
smallest = left;
//查看右节点权重是否更小 更新smallest;
if (right < minheap->size&&minheap->array[right]->freq <
minheap->array[smallest]->freq)
smallest = right;
/*如果smallest索引发生了变化(表示左子节点或右子节点的频率更小),
则使用你提供的swapMinHeapNode函数交换smallest和idx位置上的节点。
这确保了最小频率的节点被移动到堆的顶部。
最后,如果发生了交换,就递归调用minHeapify函数,
在以smallest索引为根的子树上进行堆化操作。这样确保了整个堆中的最小堆属性得以保持。*/
if (smallest!=idx){
swapMinHeapNode(&minheap->array[smallest],&minheap->array[idx]);
minHeapify(minheap, smallest);
}
}
//堆大小是否为1
int isSizeOne(struct MinHeap* minHeap) {
return(minHeap->size == 1);
}
//最小堆中提取最小值节点,并进行相应的调整以维持最小堆的性质。
struct MinHeapNode* extractMin(struct MinHeap* minheap)
{
//保存最小值节点
struct MinHeapNode* temp =minheap->array[0];
//将最后一个节点移到根节点位置
minheap->array[0] = minheap->array[minheap->size - 1];
//减小堆的大小
--minheap->size;
//调整堆
minHeapify(minheap, 0);
return temp; //返回最小值节点
}
//节点插入
void insertMinHeap(struct MinHeap* minHeap,
struct MinHeapNode* minHeapNode) {
//堆大小加一
++minHeap->size;
//初始化插入位置 即堆的最后一个位置
int i = minHeap->size -1;
//检查当前节点的频率是否小于其父节点的频率 如果小于,则需要将父节点下移一层。
while (i&&minHeapNode->freq < minHeap->array[(i - 1) / 2]->freq)
{
//将父节点移到当前位置i 为待插入节点留出位置
minHeap->array[i] = minHeap->array[(i - 1) / 2];
i = (i - 1) / 2;
}
//插入节点
minHeap->array[i] = minHeapNode;
}
void buildMinHeap(struct MinHeap* minHeap) {
int n = minHeap->size - 1;
int i;
for (i = (n - 1) / 2; i >= 0; --i)
minHeapify(minHeap, i);
}
void printArr(int arr[],int n) {
int i;
for (i = 0; i < n; ++i) {
cout << arr[i];
}
cout << "\n";
}
//检查是否叶子节点
int isLeaf(struct MinHeapNode* root) {
return !(root->left)&&!(root->right);
}
//创建和构建最小堆(MinHeap)的函数
struct MinHeap* createAndBuildMinHeap(char data[], int freq[], int size) {
struct MinHeap* minHeap = createMinHeap(size);
for (int i = 0; i < size; ++i)
minHeap->array[i] = newNode(data[i], freq[i]);
minHeap->size = size;
buildMinHeap(minHeap);
return minHeap;
}
//构建哈夫曼树
struct MinHeapNode* buildHuffmanTree(char data[],int freq[],int size)
{
struct MinHeapNode *left, *right, *top;
struct MinHeap* minHeap = createAndBuildMinHeap(data, freq, size);
while (!isSizeOne(minHeap)) {
left = extractMin(minHeap);
right = extractMin(minHeap);
top = newNode('$',left->freq+right->freq);
top->left = left;
top->right = right;
insertMinHeap(minHeap, top);
}
//提取根节点 作为返回值
return extractMin(minHeap);
}
void printCodes(struct MinHeapNode* root,int arr[],int top) {
if (root->left) {
arr[top] = 0;
printCodes(root->left, arr, top + 1);
}
if (root->right) {
arr[top] = 1;
printCodes(root->right,arr,top+1);
}
//是叶子节点 则打印编码
if (isLeaf(root)) {
cout << root->data << ":";
printArr(arr, top);
}
}
void HuffmanCodes(char data[],int freq[],int size) {
struct MinHeapNode* root = buildHuffmanTree(data,freq,size);
int arr[MAX_TREE_HT], top = 0;
printCodes(root,arr,top);
}
int main() {
char arr[] = {'a','b','c','d','e','f'};
int freq[] = {5,9,12,13,16,45};
int size = sizeof(arr) / sizeof(arr[0]);
HuffmanCodes(arr,freq,size);
return 0;
}