哈弗曼树
2015-10-27 14:46 yrpapa 阅读(331) 评论(0) 收藏 举报一,什么是哈夫曼树
什么是哈夫曼树呢?
哈夫曼树是一种带权路径长度最短的二叉树,也称为最优二叉树。下面用一幅图来说明。
它们的带权路径长度分别为:
图a: WPL=5*2+7*2+2*2+13*2=54
图b: WPL=5*3+2*3+7*2+13*1=48
可见,图b的带权路径长度较小,我们可以证明图b就是哈夫曼树(也称为最优二叉树)。
二,如何构建哈夫曼树
一般可以按下面步骤构建:
1,将所有左,右子树都为空的作为根节点。
2,在森林中选出两棵根节点的权值最小的树作为一棵新树的左,右子树,且置新树的附加根节点的权值为其左,右子树上根节点的权值之和。注意,左子树的权值应小于右子树的权值。
3,从森林中删除这两棵树,同时把新树加入到森林中。
4,重复2,3步骤,直到森林中只有一棵树为止,此树便是哈夫曼树。
下面是构建哈夫曼树的图解过程:
三,哈夫曼编码
利用哈夫曼树求得的用于通信的二进制编码称为哈夫曼编码。树中从根到每个叶子节点都有一条路径,对路径上的各分支约定指向左子树的分支表示”0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为各个叶子节点对应的字符编码,即是哈夫曼编码。
就拿上图例子来说:
A,B,C,D对应的哈夫曼编码分别为:111,10,110,0
用图说明如下:
记住,设计电文总长最短的二进制前缀编码,就是以n个字符出现的频率作为权构造一棵哈夫曼树,由哈夫曼树求得的编码就是哈夫曼编码。
#include <iostream>
using namespace std;
//********************************
//构造哈夫曼树
//********************************
/*哈夫曼树顺序表的定义*/
typedef struct
{
intweight;
intparent,lchild,rchild;
}HTNode;
typedef HTNode * HuffmanTree;
/*初始化一个哈夫曼树*/
void InitHuffmanTree(HuffmanTree&HT,int m)
{
inti;
HT=newHTNode[m];
for(i=0;i<m;i++)
{
HT[i].weight=0;
HT[i].parent=-1;
HT[i].lchild=-1;
HT[i].rchild=-1;
}
}
//****************************************
//从n个结点中选取最小的两个结点
//****************************************
void SelectMin(HuffmanTree &HT,intn,int &min1,int &min2)
{
typedefstruct
{
intNewWeight;//存储权
intp;//存储该结点所在的位置
}TempNode,*TempTree;
TempTreeTT=new TempNode[n];
inti,j;
j=0;
for(i=0;i<n;i++)
{
if(HT[i].parent==-1&& HT[i].weight!=0)
{
TT[j].NewWeight=HT[i].weight;
TT[j].p=i;
j++;
}
}//将HT中没有双亲的结点存储到TT中
intm1,m2;
m1=m2=0;
for(i=0;i<j;i++)
{
if(TT[i].NewWeight<TT[m1].NewWeight)//此处不让取到相等,是因为结点中有相同权值的时候,m1取最前的
那个。
m1=i;
}
for(i=0;i<j;i++)
{
if(m1==m2)
m2++;//当m1在第一个位置的时候,m2向后移一位
if(TT[i].NewWeight<=TT[m2].NewWeight&& i!=m1)//此处取到相等,是让在结点中有相同的权值的时候,
//m2取最后的那个。
m2=i;
}
min1=TT[m1].p;
min2=TT[m2].p;
}
/*创建哈夫曼树*/
void CreateHaffmanTree(HuffmanTree&HT,int n)
{
inti;
intm;
intmin1,min2;
if(n<=1)
cout<<"ParameterError!";
m=2*n-1;//哈夫曼树中结点的个数
InitHuffmanTree(HT,m);
for(i=0;i<n;i++)
{
cin>>HT[i].weight;
}
for(i=n;i<m;i++)
{
SelectMin(HT,i,min1,min2);
HT[min1].parent=i;
HT[min2].parent=i;
HT[i].lchild=min1;
HT[i].rchild=min2;
HT[i].weight=HT[min1].weight+HT[min2].weight;
cout<<min1<<""<<min2<<endl;
}
}
//***********************************
//构造哈夫曼编码
//***********************************
/*哈夫曼编码的定义*/
typedef struct
{
charch;
charbits[10];
}CodeNode;
typedef CodeNode * HuffmanCode;
/*哈夫曼编码的构造*/
void CreateHuffmanCode(HuffmanTree&HT,HuffmanCode &HC,int n)
{
inti;
intstart;
intc;
intp;
char*cd;
charq;
HC=newCodeNode[n];
cd=newchar[n];
cd[n-1]='/0';
for(i=0;i<n;i++)
{
cin>>q;
HC[i].ch=q;
start=n-1;
c=i;
while((p=HT[c].parent)>=0)
{
--start;
cd[start]=(HT[p].lchild==c)?'0':'1';
c=p;
}
strcpy(HC[i].bits,&cd[start]);
}
deletecd;
}
/*哈夫曼编码的输出*/
void OutputHuffmanCode(HuffmanCode&HC,int n)
{
inti;
for(i=0;i<n;i++)
{
cout<<HC[i].ch<<""<<HC[i].bits<<endl;
}
}
void main()
{
inti;
cout<<"输入字符个数:";
cin>>i;
HuffmanTreeHT;
HuffmanCodeHC;
CreateHaffmanTree(HT,i);
CreateHuffmanCode(HT,HC,i);
OutputHuffmanCode(HC,i);
}
Template 编程:
// Heap.cpp : 定义控制台应用程序的入口点.
// Heap Sort C++ file.
// 2014-09-04.
// WangChenYang.
#include "stdafx.h"
#include <iostream>
using namespace std;
template<typename T>
void Max_Heapify(T data[], int i, int heapsize);
template<typename T>
void Bulid_Max_Heap(T data[], int heapsize);
template<typename T>
void Heap_Sort(T data[], int heapsize);
int _tmain(int argc, _TCHAR* argv[])
{
int data[10] = { 71, 18, 151, 138, 160, 63, 174, 169, 79, 78 };
cout << "Heap Sort Algorithms :" << endl;
cout << endl << "The data before Heap Sort :";
for (int i = 0; i<10; i++)
cout << data[i] << " ";
cout << endl;
Heap_Sort(data, 10);
cout << "The data after Heap Sort :";
for (int i = 0; i<10; i++)
cout << data[i] << " ";
cout << endl;
return 0;
}
// Below Algorithms come from the book : << Introduction to Algorithms .2th >>
template<typename T>
void Max_Heapify(T data[], int i, int heapsize)
{ //以某个节点为根节点的子树进行调整,调整为大顶堆。
int left = 2 * i + 1;
int right = 2 * i + 2;
int largest = i;
if (left < heapsize && data[left] > data[i])
largest = left;
if (right < heapsize && data[right] > data[largest])
largest = right;
if (largest != i)
{
// swap largest and i.
int temp = data[largest];
data[largest] = data[i];
data[i] = temp;
Max_Heapify(data, largest, heapsize);
// 这个函数开始执行之前默认左右子树已经是最大堆(由Bulid_Max_Heap函数中的循环方式决定)
// 所以这里只要一个语句。
}
}
template<typename T>
void Bulid_Max_Heap(T data[], int heapsize)
{ //建堆的过程
for (int i = heapsize / 2 - 1; i >= 0; i--)
Max_Heapify(data, i, heapsize);
//只需要对除了叶子节点以外的节点进行调整
}
template<typename T>
void Heap_Sort(T data[], int heapsize)
{
//堆排序算法实现主体:先用bulid_max_heap将输入数组构造成大顶堆,
//然后将data[0]和堆的最后一个元数交换,继续进行调整。
Bulid_Max_Heap(data, heapsize);
for (int i = heapsize - 1; i > 0; i--)
{
int t = data[0];
data[0] = data[i];
data[i] = t;
Max_Heapify(data, 0, i);
}
}
/* The result
Heap Sort Algorithms :
The data before Heap Sort :71 18 151 138 160 63 174 169 79 78
The data after Heap Sort :18 63 71 78 79 138 151 160 169 174
请按任意键继续. . .
*/



浙公网安备 33010602011771号