#include<iostream>
#include<cstring>
using namespace std;
#define OK 1
#define ERROR 0
#define SIZE 27
typedef bool Status;
typedef struct {
char code;
unsigned int weight;
unsigned int parent,lchild,rchild;
}HTNode,*HuffmanTree;
typedef char **HuffmanCode;//动态分配数组存储哈夫曼编码
int here, flag;
Status Select(HuffmanTree HT,int m,int &s1,int &s2){ //找出当前没有被使用过的两个最小的节点
int min1 = 0x3f3f3f3f;
int min2 = 0x3f3f3f3f;
HuffmanTree p = HT + 1;
for(int i = 1; i <= m; i ++ , p ++){
if(p->parent == 0 && min1 > p->weight){
min1 = p->weight;
s1 = i;
}
}
p = HT + 1;
for(int i = 1; i <= m; i ++ , p ++ ){
if(i != s1 && p->parent == 0)
if(p->weight < min2){
min2 = p->weight;
s2 = i;
}
}
return 1;
}
Status Scanf(int *w){
int cnt = 0;
int *p = w;
while(cnt <= 26){
cin >> *p;
if(*p > 0){
cnt ++ ;
p ++ ;
}
else{
cout<<"输入错误,请重新输入"<<endl;
}
}
return 1;
}
Status InitHuffmanTree(HuffmanTree &HT,int *w,int n){//初始化哈夫曼树
int m = 2 * n - 1;
HT=(HuffmanTree)malloc((m + 1)*sizeof(HTNode));
if(!HT) return 0;
HuffmanTree q = HT + 1;//0节点未使用
for(int i = 1;i <= n; i ++ , q ++ , w ++ ){
q->code='l';//给叶子节点设标记
q->weight = *w;
q->parent = 0;
q->lchild = 0;
q->rchild = 0;
}//将n个叶子结点遍历,赋初值为0
for(int i = n + 1; i <= m; i ++ , q ++ ){
q->code='f';//证明为非叶子节点
q->weight = 0;
q->parent = 0;
q->lchild = 0;
q->rchild = 0;
}//将剩余所有结点初始化权值为0
return 1;
}
Status CreatHuffmanCode(HuffmanTree &HT, HuffmanCode &HC, int n){
if(n <= 1) return 0;
int m = 2 * n - 1; //Huffman数总结点个数
int s1,s2;
int st;//st 开始指向最后,即编码结束符位置
int cnt,f;
for(int i = n + 1; i <= m; i ++ ){
Select(HT, i - 1, s1, s2);//选parent为0的最小的两结点
(HT + s1)->parent = i;
(HT + s2)->parent = i;
(HT + i)->lchild = s1;
(HT + i)->rchild = s2;
(HT + i)->weight = (HT + s1)->weight+(HT + s2)->weight;
}//为非叶节点的结点赋值
HC = (HuffmanCode)malloc((n + 1)*sizeof(char*));//分配储存n个字符编码的编码表空间
if(!HC)return 0;
char*cd = (char*)malloc(n * sizeof(char));//分配临时存储字符编码的动态空间
*(cd + (n - 1)) = '\0';//编码结束符
for(int i = 1; i <= n; i ++ ){//从叶子节点开始逐个求编码
st = n - 1;
for(cnt = i,f = (HT + i)->parent; f != 0; cnt = f, f = (HT + f)->parent){
if((HT + f)->lchild == cnt){
cd[ -- st] = '0';
}
else{
cd[ -- st] = '1';
}
}
HC[i] = (char*)malloc((n - st)*sizeof(char));//n-st巧妙的节省了空间
strcpy(HC[i], &cd[st]);//把求得编码的首地址从cd[st]复制到HC的当前行中
}
free(cd);
return 1;
}
Status CoutCode(HuffmanTree HT, HuffmanCode HC, int *w){//遍历输出
cout<<"字符"<<" "<<"编码"<<endl;
char ch = 'a';
int *p = w;
for(int i = 1; i <= 27; i ++ ){
if(i == 27){
cout<<" ";
}
else{
printf("%c",ch + i - 1);
}
cout<<" ";
cout<<HC[i]<<endl;
}
return 1;
}
Status TransCode(HuffmanTree &HT,int n){
char ch[80];
int i = 0, m = 2 * n - 1;
cin>>ch;
cout<<"输入的二进制编码翻译成的字符为:";
while(ch[i] && ch[i] != '\u0000'){
if(ch[i] == '0'){
m = (HT + m)->lchild;//如果编码表示是左孩子,就继续向左下遍历
}
if(ch[i]=='1'){
m = (HT + m)->rchild;//如果编码表示是右孩子,就继续向右下遍历
}
if((HT + m)->code == 'l'){ //如果当前遍历到的节点是叶节点
if(m == 27){
cout<<" ";
}
else{
printf("%c",'a' + m - 1);
}
m = 2 * n - 1; //将结点重新放到哈夫曼树的根节点位置,重新开始,直到所有密码编译完成
}
i++; //i自增
}
return 1;
}
Status TransString(HuffmanTree &HT, HuffmanCode HC){
char ch[105];
cout<<"请输入要进行编译的字符串:";
int g;
char c;
int k = 0;
while((c=getchar())!='%'){//在遇到字符串结尾之前
ch[k]=c;
k++;
}
ch[k] = '\0';
cout<<"该字符串的编译结果为:";
for(int i = 1; ch[i]; i ++ ){
if(ch[i] == ' '){
cout<<HC['{' - 'a' + 1];
}
else{
cout<<HC[ch[i] - 'a' + 1];
}
}
return 1;
}
void Menu(){
cout<<"********************************************************"<<endl;
cout<<"* 1.输入HuffmanTree的参数 *"<<endl;
cout<<"* 2.初始化HuffmanTree参数(含有26字母及空格) *"<<endl;
cout<<"* 3.创建HuffmanTree和编码表 *"<<endl;
cout<<"* 4.输出编码表 *"<<endl;
cout<<"* 5.输入编码,并翻译为字符 *"<<endl;
cout<<"* 6.输入字符,并实现转码 *"<<endl;
cout<<"* 7.退出 *"<<endl;
cout<<"********************************************************"<<endl;
cout<<"请选择你要进行的操作:";
}
int main()
{
HuffmanTree HT;
HuffmanCode HC;
int n = 27;
bool flag1 = false;//标记哈夫曼树和编码表是否建立
bool flag2 = false;//标记是否已输入参数
int *w = (int*)malloc(n * sizeof(int));
if(!w) exit(-1);
while(1){
Menu();
int x;
cin>>x;
if(x == 1){
cout<<"请输入参数:";
Scanf(w);
cout<<"输入完成"<<endl;
flag2 = true;
}
else if(x == 2){
if(flag2){
InitHuffmanTree(HT,w,n);
cout<<"HuffmanTree初始化成功!"<<endl;
}
else cout<<"请先输入Huffman的参数!"<<endl;
}
else if(x == 3){
if(flag2){
CreatHuffmanCode(HT, HC, n);
cout<<"创建成功!"<<endl;
flag1 = true;
}
else cout<<"请先输入Huffman参数或初始化!"<<endl;
}
else if(x == 4){
if(flag1){
cout<<"编码表为:"<<endl;
CoutCode(HT, HC, w);
}
else cout<<"请先创建HuffmanTree和编码表!"<<endl;
}
else if(x == 5){
if(flag1){
cout<<"请输入编码:";
TransCode(HT,n);
cout<<endl;
}
else cout<<"请先创建HuffmanTree和编码表!"<<endl;
}
else if(x == 6){
if(flag1){
cout<<"请输入字符串(以%结尾):";
TransString(HT, HC);
cout<<endl;
}
else cout<<"请先创建HuffmanTree和编码表!"<<endl;
}
else if(x == 7){
cout<<"感谢使用!";
break;
}
else{
cout<<"请输入正确的操作序号"<<endl;
}
cout<<endl;
}
return 0;
}
数据结构-哈夫曼树
最新推荐文章于 2024-08-27 22:35:52 发布