Huffman的特点是每次取出优先队列,也即是堆中最小的两个节点链接成一个新的节点,将新的节点放回到堆中。
Huffman树每一个叶子都是一个字符。非叶子节点只是我们生成的节点,不是我们需要编码的字符。
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<queue>
#define LEN 20
using namespace std;
typedef char ElementType;
typedef int Location;
struct cmp{
template<typename T, typename U>
bool operator()(T const& left, U const &right) {
if (left.first > right.first) return true;
return false;
}
};
struct LetterNode{ //Letter为Huffman树节点
int weight;
ElementType Data;
char* huffman_code;
int Left;
int Right;
};
typedef LetterNode *Letter;
int LetterWeight[] = {186,64,13,22,32,103,21,15,47,57,1,5,32,20,57,63,15,1,48,51,80,23,8,18,1,16,1};
ElementType LetterData[] = {' ','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
//1.建造Huffman树
Location BuildLetterHuffman(int LetterWeight[], ElementType LetterData[],int LetterLength,LetterNode LetterHuTree[])
{
Letter L;
int Le,Ri;
int LeftNode,RightNode;
int Count ;
Count = LetterLength;
for(int i = 0; i < LetterLength; i++)
{
L = (Letter)malloc(sizeof(LetterNode));
L->Data = LetterData[i];
L->weight = LetterWeight[i];
L->Left = -1; //已经得到了字母表
L->Right = -1;
L->huffman_code = (char*)malloc(10 * sizeof(char));
LetterHuTree[i] = *L;
}
//将权值数组放入堆中
priority_queue<pair<int, int>, vector<pair<int, int> >, cmp> MinHeap;
for(int i = 0; i <LetterLength ; i++)
{
pair<int, int> LEW(LetterWeight[i],i);
MinHeap.push(LEW);
}
//注意此处最小堆中应没有节点足够组成新节点了
for(int i = 0;(MinHeap.size() != 0) && (MinHeap.size() != 1); i++) //在此处循环条件要注意!!!!因为有可能已经有子节点的树会再次链接!!!!!
{
//1.选取出数组中最小的两个元素
LeftNode = MinHeap.top().second;
MinHeap.pop();
RightNode = MinHeap.top().second;
MinHeap.pop();
//2.构建新的Huffman节点
L = (Letter)malloc(sizeof(LetterNode));
L->weight = LetterHuTree[LeftNode].weight + LetterHuTree[RightNode].weight;
L->Left = LeftNode;
L->Data = 'M';
L->huffman_code = (char*)malloc(10 * sizeof(char));
L->Right = RightNode;
LetterHuTree[Count] = *L;
//3.将新生Huffman节点放入堆中
pair<int, int> LEW(LetterHuTree[Count].weight,Count);
MinHeap.push(LEW);
Count++;
}
Count--;
return Count; //此时L为构建的最后节点,即为Huffman树的根节点
}
//2.对已经构建好的霍夫曼树的节点进行编码
void HuffmanCode(Letter L,Location location,string code)
{
string NowCode = code;
strcpy(L[location].huffman_code , NowCode.c_str());
// cout <<L[location].Data << "的Huffman编码是" <<L[location].huffman_code <<endl;
if(L[location].Left != -1)
{
code = code + "0";
HuffmanCode(L,L[location].Left,code);
}
if(L[location].Right != -1)
{
NowCode = NowCode + "1";
HuffmanCode(L,L[location].Right,NowCode);
}
}
//3.打印出编辑完成的Huffman编码
void PrintHuCode(Letter L,int LetterLength) //打印Huffman数组元素中的编码
{
cout << "该权值下的Huffman编码为:\n";
for(int i = 0; i < LetterLength; i++)
{
cout <<L[i].Data<< "的编码为"<<L[i].huffman_code <<endl;
// printf("%c的编码为%s\n",L[i].Data,L[i].huffman_code);
}
}
int main()
{
// int a = 0;
// for(int i = 0 ; i< 27;i++)
// {
// a += LetterWeight[i];
// }
// cout <<"a的值为:\n";
// cout << a;
LetterNode LetterHuTree[100];
Location HuLocation = BuildLetterHuffman(LetterWeight, LetterData,27,LetterHuTree);
HuffmanCode(LetterHuTree,HuLocation," ");
PrintHuCode(LetterHuTree,27);
return 0;
}