赞
踩
概念上说,哈夫曼树是给定一组具有确定权值的叶子结点,带权路径长度最小的二叉树。
由给定的n个权值{w1,w2,…,wn}构造n棵只有一个根结点的二叉树,从而得到一个二叉树集合F={T1,T2,…,Tn};
在F中选取根结点的权值最小的两棵二叉树分别作为左、右子树构造一棵新的二叉树,这棵新二叉树的根结点的权值为其左、右子树根结点的权值之和;
在F中删除作为左、右子树的两棵二叉树,并将新建立的二叉树加入到F中;
我们选择权值最小的两个叶子结点,将其相加作为新的叶子结点
在这可能读者会有疑问,为什么不选第三个5呢?答案是当然可以选,这也说明了我们构造的哈夫曼树可能并不唯一,但效果是一样的
到这一颗哈夫曼树就被我们构造出来了,是不是很简单呢?这就是哈夫曼算法
至于为什么是2n-1,在后面我会讲到
其中:weight:权值域,保存该结点的权值;
lchild:指针域,结点的左孩子结点在数组中的下标;
rchild:指针域,结点的右孩子结点在数组中的下标;
parent:指针域,该结点的双亲结点在数组中的下标。
void HuffmanTree(element huffTree[ ], int w[ ], int n ) { for (i = 0; i <2*n-1; i++) { huffTree [i].parent = -1; huffTree [i].lchild = -1; huffTree [i].rchild = -1; }//全部置为-1 for (i = 0; i < n; i++) huffTree[i].weight = w[i];//前n个元素的权重赋值进去 for (k = n; k < 2*n-1; k++) { Select(huffTree, 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; } }
#include<iostream> #include<fstream>//文件输入流的头文件 #include<conio.h>//getch()函数头文件 #include<string>//新版vc的getch()函数头文件 using namespace std; char OutputCode[1000];//待输出的哈夫曼编码 string HuffCode[26];//哈夫曼编码 char sentence[100]; struct element { char data;//数据 double weight;//权重 bool root_flag;//判断是否被标记为根结点 int lchild,rchild,parent; }; void HuffmanTree(element huffTree[],int n); void Select(element huffTree[],int n,int &i1,int &i2); void DFS_PreOrder(element huffTree[],int i,int k); void translate(string HuffCode[],char sentence[]); int main() { fstream fcin; fcin.open("HuffTree.txt",ios::in); int N=0; element huffTree[100]; while(!fcin.eof()) { fcin>>huffTree[N].data>>huffTree[N].weight;//写入哈夫曼树的结点数据值,和数据所对应的权重 N++; } HuffmanTree(huffTree,N);//构造哈夫曼树 DFS_PreOrder(huffTree,2*N-2,0);//前序深度优先遍历哈夫曼树 system("CLS"); fcin.close(); //功能模块 char X; int i=0; system("color A0"); while(true) { cout<<"请输入需要的功能N:"<<endl; cout<<"0.退出\n"; cout<<"1.输出各个字母所对应的哈夫曼编码\n"; cout<<"2.将句子翻译成哈夫曼编码\n"; cin>>X; if(X=='0')break;//输入'0'退出 switch(X) { case '1': DFS_PreOrder(huffTree,2*N-2,0);//前序深度优先遍历哈夫曼树 cout<<"--请按任意键继续--\n"; _getch(); system("CLS"); break; case '2': sentence[0]='\0'; cout<<"请输入要翻译的英文序列:"; cin>>sentence; translate(HuffCode,sentence);//翻译成哈夫曼编码 cout<<"--请按任意键继续--\n"; _getch(); system("CLS"); break; default: cout<<"输入错误,请重新输入!\n"; cout<<"--请按任意键继续--\n"; _getch(); system("CLS"); } } return 0; } void HuffmanTree(element huffTree[],int n) { int i; for(i=0;i<2*n-1;i++) { huffTree[i].parent=-1; huffTree[i].lchild=-1; huffTree[i].rchild=-1; huffTree[i].root_flag=0;//初始化时,令root_flag=0,即所有的结点都不是根结点 } for(i=0;i<n;i++) huffTree[i].root_flag=1;//然后,令叶子结点的根结点属性全为1,即叶子结点都设置为根结点 int i1=-1,i2=-1;//将权重最小的两个点初始化为-1 for(int k=n;k<2*n-1;k++) { huffTree[k].data='#';//让哈夫曼树上非叶子结点的数据为'#',即空数据 Select(huffTree,n,i1,i2);//寻找两个权重最小的根结点 huffTree[i1].parent=k; huffTree[i2].parent=k;//两个根结点的parent设置为k huffTree[k].lchild=i1; huffTree[k].rchild=i2;//k结点的左右孩子设置为i1,i2 huffTree[k].weight=huffTree[i1].weight+huffTree[i2].weight;//k结点的权重等于i1,i2的权重相加 huffTree[k].root_flag=1;//把k结点标记为根结点 huffTree[i1].root_flag=0; huffTree[i2].root_flag=0;//把i1,i2结点标记为非根结点 } } void Select(element huffTree[],int n,int &i1,int &i2)//寻找两个权重最小的根结点函数,这里的i1,i2设置为 &变量名,即函数会对这两个变量的值进行修改 { int i; double weight=1000;//初始化权重为一个大数 for(i=0;i<2*n-1;i++)//先遍历一遍求i1 if(huffTree[i].root_flag&&huffTree[i].weight<weight)//如果是根节点 则找出最小的为i1 { weight=huffTree[i].weight; i1=i; } weight=1000;//再次设置权重为一个大数求i2 for(i=0;i<2*n-1;i++)//再遍历一遍求i2 if(huffTree[i].root_flag&&huffTree[i].weight<weight&&i!=i1)//如果是根节点并且不是i1,则找出最小的为i2 { weight=huffTree[i].weight; i2=i; } } void DFS_PreOrder(element huffTree[],int i,int k)//前序深度优先遍历哈夫曼树,这里的i参数是根结点的数组下标,k结点是哈夫曼编码的数组下标 { if(huffTree[i].lchild!=-1)//如果有左孩子,则遍历左子树 { OutputCode[k]='0';//遍历一次左子树,把哈夫曼编码置0 DFS_PreOrder(huffTree,huffTree[i].lchild,k+1); } if(huffTree[i].rchild!=-1)//如果有右孩子,则遍历右子树 { OutputCode[k]='1';//遍历一次右子树,把哈夫曼编码置1 DFS_PreOrder(huffTree,huffTree[i].rchild,k+1); } if(huffTree[i].data!='#')//如果左子树右子树都不存在,则是叶子结点,这时候需要输出结点 { OutputCode[k]='\0';//给哈夫曼编码结束符 cout<<huffTree[i].data<<"的编码为:"; for(int t=0;OutputCode[t]!='\0';t++) cout<<OutputCode[t];//输出哈夫曼编码 cout<<endl; HuffCode[huffTree[i].data-'A']=OutputCode;//保存下来该字母的哈夫曼编码 } } void translate(string HuffCode[],char sentence[])//翻译函数 { int i=0; cout<<"翻译后的哈夫曼编码为:"; while(sentence[i]!='\0') { if(sentence[i]>='a'&&sentence[i]<='z') cout<<HuffCode[sentence[i]-'a']; else if(sentence[i]>='A'&&sentence[i]<='Z') cout<<HuffCode[sentence[i]-'A']; i++; } cout<<endl; }
E 12.25 T 9.41 A 8.19 O 7.26 I 7.10 N 7.06 R 6.85 S 6.36 H 4.57 D 3.91 C 3.83 L 3.77 M 3.34 P 2.89 U 2.58 F 2.26 G 1.71 W 1.59 Y 1.58 B 1.47 K 0.41 J 0.14 V 1.09 X 0.21 Q 0.09 Z 0.08
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。