一.相关概念
1.叶子结点的权值:
通常表示该结点的访问次数
2.哈夫曼树:
给定一组有确定权值的叶子结点,带权路径长度最小的二叉树。
3.哈夫曼树的特点:
1.权值越大的叶子结点越靠近根节点,权值越小的叶子结点越远离根节点。
2.只有度为0和度为2的结点。
4.哈夫曼算法基本思想:
(1)初始化:
由给定的 n个权值构造n棵只有一个根结点的二叉树,从而得到一个二叉树集合。
(2)选取与合并:
在二叉树集合中选取根节点的权值最小的两颗二叉树分别作为左、右子树构造一颗新的二叉树,这颗新的二叉树的根结点的权值为其左、右子树根结点的权值之和。
(3)删除与加入
在二叉树集合中删去作为左、右子树的二叉树,并将新建立的二叉树加入到二叉树结合中。
(4)重复
重复(2)(3)两步,直到二叉树集合中只剩下一颗二叉树。
二.哈夫曼算法的存储结构
struct element{
int weight;
int lchild,rchild,parent;
};
设置一个数组 huffTree[2n-1]
三.伪代码
1.数组huffTree初始化
所有元素结点的双亲、左右孩子都置为-1.
2.给定权值
数组huffTree的前n个元素的权值给定
3.进行n-1次合并
3.1 在二叉树集合中选取两个权值最小的根结点,其下标为i1,i2
3.2 将二叉树i1,i2合并为一棵新的二叉树
四.代码实现
//哈夫曼树
#include <iostream>
using namespace std;
struct element{
int weight;
int lchild,rchild,parent;
};
void select(element hufftree[],int k,int &i1,int &i2){
for(int i=0;i<k;i++){//先初始化i1,i2
if(hufftree[i].parent==-1){
i1=i2=i;
break;
}
}
for(int i=0;i<k;i++){
if(hufftree[i].parent==-1&&hufftree[i].weight<hufftree[i1].weight){
i1=i;
}
}
for(int i=0;i<k;i++){
if(hufftree[i].parent==-1&&hufftree[i].weight<hufftree[i2].weight&&i!=i1){
i2=i;
}
}
cout<<"最小下标"<<i1<<"次小下表"<<i2<<endl;
}
void huffmanTree(element hufftree[],int w[],int n){
int i1,i2;
for(int i=0;i<2*n-1;i++){//初始化
hufftree[i].parent=-1;
hufftree[i].lchild=-1;
hufftree[i].rchild=-1;
}
for(int i=0;i<n;i++){//权值初始化
hufftree[i].weight=w[i];
}
for(int k=0;k<2*n-1;k++){
select(hufftree, k, i1, i2);
hufftree[k].weight=hufftree[i1].weight+hufftree[i2].weight;
hufftree[i1].parent=k;
hufftree[i2].parent=k;
hufftree[k].lchild=i1;
hufftree[k].rchild=i2;
}
}
int main(int argc, const char * argv[]) {
int n,*w;
cout<<"请输入结点个数:"<<endl;
cin>>n;
const int x=n;
w=new int[x];
element *huffTree=new element[x];
cout<<"请输入"<<n<<"个权值:"<<endl;
huffmanTree(huffTree, w, n);
cout<<"打印构建好的哈夫曼树数组下标"<<endl;
cout<<"weight\t"<<"parent\t"<<"lchild\t"<<"rchild\t"<<endl;
for(int i=0;i<n;i++){
cout<<huffTree[i].weight<<"\t";
cout<<huffTree[i].parent<<"\t";
cout<<huffTree[i].lchild<<"\t";
cout<<huffTree[i].rchild<<"\t";
cout<<endl;
}
delete []w;
delete []huffTree;
return 0;
}