纠结了两天,终于解决了这个问题,分享给大家自己的思路。
将一组无序数列建立最小堆,从最小堆中弹出两个最小的元素作为左右儿子其和为父节点构建一个树,将父节点加入最小堆,再次调用以上方法重复构建树,最终即可构建一棵哈夫曼树,哈夫曼树的特点有3个:1、 所有的序列元素集中在叶节点上 2、没有度为1的节点 3、哈夫曼树的任意非叶节点的左右子树交换后仍是哈夫曼树 4、n个叶子结点的哈夫曼树共有2n-1个结点
哈夫曼树的具体建立算法如下:
typedef struct TreeNode *HuffmanTree;
struct TreeNode{
int Weight;
HuffmanTree Left, Right;
}
HuffmanTree Huffman( MinHeap H )
{ /* 假设H->Size个权值已经存在H->Elements[]->Weight里 */
int i; HuffmanTree T;
BuildMinHeap(H); /*将H->Elements[]按权值调整为最小堆*/
for (i = 1; i < H->Size; i++) { /*做H->Size-1次合并*/
T = malloc( sizeof( struct TreeNode) ); /*建立新结点*/
T->Left = DeleteMin(H);
/*从最小堆中删除一个结点,作为新T的左子结点*/
T->Right = DeleteMin(H);
/*从最小堆中删除一个结点,作为新T的右子结点*/
T->Weight = T->Left->Weight+T->Right->Weight;
/*计算新权值*/
Insert( H, T ); /*将新T插入最小堆*/
}
T = DeleteMin(H);
return T;
}
编码根据建立的哈夫曼树,从根节点开始遍历,向左开始时记录0,向右开始时记录1,遍历到叶节点时,记录元素键值及所有路径标记的01代码,从而实现编码。解码根据得到的编码对应关系,遍历解码对象字符串,从所有编码里依次寻找匹配,若成功则记录并从该位置开始匹配剩余字符串。
哈夫曼树的建立与编码及解码的C++实现源代码如下:
//huffmantree.h
#ifndef HUFFMANTREE_H
#define HUFFMANTREE_H
#include <IOSTREAM>
#include <STRING>
#include <MAP>
typedef struct HuffmanNode* pHuffmanNode;
struct HuffmanNode
{
int data;
pHuffmanNode left,right;
};
class MinHeap
{
private:
pHuffmanNode Data[100];
int Size;
int Capacity;
public:
MinHeap():Size(0),Capacity(100)
{
//Data=new HuffmanNode[Capacity];
Data[0]=NULL;
}
~MinHeap(){}
bool Insert(pHuffmanNode);
pHuffmanNode DeleteMin();
bool IsFull(){return Size==Capacity-1;}
bool IsEmpty(){return Size==0;}
void Print();
int GetSize(){return Size;}
};
bool MinHeap::Insert(pHuffmanNode x)
{
if(IsFull())
return false;
for(int i=++Size;i>1&&Data[i/2]->data>x->data;i/=2)
{
Data[i]=Data[i/2];
}
Data[i]=x;
return true;
}
pHuffmanNode MinHeap::DeleteMin()
{
/*if(IsEmpty())
return Type(-1111);*/
pHuffmanNode temp=Data[1];
pHuffmanNode last=Data[Size--];
int parent,child;
for(parent=1;2*parent<=Size;parent=child)
{
child=parent*2;
if(2*parent+1<=Size&&Data[2*parent]->data>Data[2*parent+1]->data)
child++;
if(last->data>Data[child]->data)
Data[parent]=Data[child];
else
break;
}
Data[parent]=last;
return temp;
}
void MinHeap::Print()
{
for(int i=1;i<=Size;i++)
{
std::cout<<Data[i]->data<<" ";
}
std::cout<<std::endl;
}
class HuffmanTree
{
private:
pHuffmanNode root;
MinHeap minheap;
char code[11][10];
public:
HuffmanTree():root(NULL){
for(int i=0;i<11;i++)
for(int j=0;j<10;j++)
code[i][j]=' ';
}
~HuffmanTree();
void ReleaseHuffmanTreeNode(pHuffmanNode);
pHuffmanNode CreateHuffmanTree(int* a,int length);
void BuildMinHeap(int*,int);
void PrintPreOrder();
void PrintInOrder();
void PreOrderTraversal(pHuffmanNode);
void InOrderTraversal(pHuffmanNode);
void EnCode();
void DeCode(char*,int);
void MakeCode(int i,char* temp,pHuffmanNode pNode);
};
pHuffmanNode HuffmanTree::CreateHuffmanTree(int* a,int length)
{
BuildMinHeap(a,length);
while(1)
{
if(minheap.GetSize()==1)
return root;
HuffmanNode* temp1;
HuffmanNode* temp2;
temp1=minheap.DeleteMin();
temp2=minheap.DeleteMin();
if(!temp2)
return root;
HuffmanNode* temp3=new HuffmanNode;
temp3->data=temp1->data+temp2->data;
temp3->left=temp1;
temp3->right=temp2;
minheap.Insert(temp3);
root=temp3;
}
return root;
}
void HuffmanTree::BuildMinHeap(int* a,int length)
{
for(int i=0;i<length;i++)
{
HuffmanNode* sample=new HuffmanNode;
sample->data=a[i];
sample->left=sample->right=NULL;
minheap.Insert(sample);
}
}
void HuffmanTree::PrintPreOrder()
{
PreOrderTraversal(root);
}
void HuffmanTree::PreOrderTraversal(pHuffmanNode temp)
{
if(!temp)
return;
std::cout<<temp->data<<" ";
PreOrderTraversal(temp->left);
PreOrderTraversal(temp->right);
}
void HuffmanTree::PrintInOrder()
{
InOrderTraversal(root);
}
void HuffmanTree::InOrderTraversal(pHuffmanNode temp)
{
if(!temp)
return;
InOrderTraversal(temp->left);
std::cout<<temp->data<<" ";
InOrderTraversal(temp->right);
}
HuffmanTree::~HuffmanTree()
{
ReleaseHuffmanTreeNode(root);
}
void HuffmanTree::ReleaseHuffmanTreeNode(pHuffmanNode temp)
{
if(!temp)
return;
ReleaseHuffmanTreeNode(temp->left);
ReleaseHuffmanTreeNode(temp->right);
}
void HuffmanTree::EnCode()
{
char temp[10]={'0'};
MakeCode(-1,temp,root);
for(int i=1;i<11;i++)
{
std::cout<<i<<": ";
for(int j=0;j<10;j++)
{
std::cout<<code[i][j];
}
std::cout<<std::endl;
}
}
void HuffmanTree::MakeCode(int i,char* temp,pHuffmanNode pNode)
{
//遍历该哈夫曼树
if(!pNode->left&&!pNode->right)
{
for(int j=0;j<=i;j++)
code[pNode->data][j]=temp[j];
return;
}
temp[i+1]='0';
MakeCode(i+1,temp,pNode->left);
temp[i+1]='1';
MakeCode(i+1,temp,pNode->right);
}
void HuffmanTree::DeCode(char* str,int length)
{
int deCodeNum[100]={0};
int orderOfCode=0;
for(int i=0;i<length;i++)
{
for(int j=1;j<11;j++)
{
int k=i;
int l=0;
bool bCodeIn=false;
while(code[j][l]==str[k])
{
bCodeIn=true;
k++;
l++;
}
if(code[j][l]==' '&&bCodeIn)
{
//当str中的前k位与code[j]的前k位相同时
deCodeNum[orderOfCode++]=j;
i=k-1;
break;
}
}
}
for(i=0;i<orderOfCode;i++)
{
std::cout<<deCodeNum[i]<<" ";
}
std::cout<<std::endl;
}
#endif