哈夫曼编译码器.docx
《哈夫曼编译码器.docx》由会员分享,可在线阅读,更多相关《哈夫曼编译码器.docx(54页珍藏版)》请在冰豆网上搜索。
哈夫曼编译码器
《数据结构--C++实现》
学院:
计算机学院
专业班级:
软件工程
课程设计报告
题目:
哈夫曼编/译码器
【问题描述】利用哈夫曼编码可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对传输数据预先编码,在接收端将传来的数据进行译码。
对于双工信道,每端都需要一个完整的编/译码器。
试为这样的通信端编写一个哈夫曼编/译码器。
1.需求分析
1.运行环境(软、硬件环境)
Visualstudio2008
2.程序实现的功能
初始化:
输入一串字符(正文),计算不同字符(包括空格)的数目以及每种字符出现的频率(以该种字符出现的次数作为其出现频率),根据权值建立哈夫曼树,输出每一种字符的哈夫曼编码。
编码:
利用求出的哈夫曼编码,对该正文(字符串)进行编码,并输出。
译码:
对于得到的一串编码,利用已求得的哈夫曼编码进行译码,将译出的正文输出。
输出哈夫曼树形态:
以树的形式输出哈夫曼树。
3.程序的输入
一串字符(英文)或短文(英文)
4.程序的输出
根据用户需求不同有相应的输出
5.测试数据
therearethreestudents
2.设计说明
1.算法设计的思想
建立链表类、栈类、队列类、哈夫曼结点类、哈夫曼树类,通过主函数调用的方法来实现程序的功能。
2.主要的数据结构说明
链表模板类:
template//模板链表类
classLinkList
{
private:
HuaffmanTreeNode*head;//链表的头结点
public:
TypeList[1000];
LinkList(void);
~LinkList(void);
HuaffmanTreeNode*GetHead();//
voidSetHead(HuaffmanTreeNode*h);//
voidInsert(HuaffmanTreeNode*p);//
HuaffmanTreeNode*IsTheSame(HuaffmanTreeNode*pa);//判断pa是否有相同的结点,如果有相同返回该结点,否则返回NULL
voidCreateList();//创建一个哈弗曼结点的链表
intGetLength();
HuaffmanTreeNode*Delete(HuaffmanTreeNode*p);//删除结点
HuaffmanTreeNode*Copy();//复制链表
boolCheckAllTure();//检查是否全部加入哈弗曼树
};
栈模板类:
template//模板栈类
classStack
{
private:
TData[MAX];
inttop;
public:
Stack();//构造函数
boolpush(Tnum);//进栈操作
Tpop();//出栈操作
TGet_top();//得到栈顶的元素
boolEmpty();//判断栈是否为空
boolFull();//判断栈是否已满
voidClear();//清空栈
};
队列模板类:
template//模板队列类
classQueue
{
private:
Tnum[MAX];//队列中的数据元素
intfront,rear;//队首,队尾的标志
public:
Queue(void);//构造函数
~Queue(void);//析构函数
voidEnQueue(Tp);//入队操作
TDeQueue();//出队操作
boolIsEmpty();//判断队列是否为空
boolIsFull();//判断队列是否已满
voidClear();//清空队列
};
哈夫曼结点模板类:
template//模板哈夫曼结点类
classHuaffmanTreeNode
{
private:
intKey;//该字符出现的次数;
TypeData;//输入的字符元素;
HuaffmanTreeNode*parent;//双亲结点指针;
HuaffmanTreeNode*lchild;//左孩子结点指针;
HuaffmanTreeNode*rchild;//右孩子结点指针;
intTag;//记录该结点是双亲的左右孩子,左孩子为,有孩子为;
HuaffmanTreeNode*next;//下一个结点,用于链表
boolFlag;//标记该结点是否已经计入哈弗曼树
public:
HuaffmanTreeNode(void);//默认构造函数;
HuaffmanTreeNode(intk,Typed,intt,HuaffmanTreeNode*p=NULL,HuaffmanTreeNode*l=NULL,HuaffmanTreeNode*r=NULL);//构造函数
~HuaffmanTreeNode(void);//默认析构函数;
intGetKey();//得到该结点在正文中出现的次数
voidSetKey(intkey);//设置关键字的次数
TypeGetData();//得到该结点对应的文字编码
voidSetData(Typedata);//设置结点的文字编码
HuaffmanTreeNode*GetParent();//得到该结点的双亲结点
voidSetParent(HuaffmanTreeNode*p);//设置双亲结点
HuaffmanTreeNode*GetLchild();//得到左孩子结点
voidSetLchild(HuaffmanTreeNode*p);//设置左孩子结点
HuaffmanTreeNode*GetRchild();//得到右孩子结点
voidSetRchild(HuaffmanTreeNode*p);//设置右孩子结点
intGetTag();//得到标记
voidSetTag(intt);//设置标记
HuaffmanTreeNode*GetNext();//得到下一个结点
voidSetNext(HuaffmanTreeNode*p);//设置下一个结点
boolGetFlag(){returnFlag;}
voidSetFlag(booltag){Flag=tag;}
};
哈夫曼树模板类:
template//模板哈夫曼树类
classHuaffmanTree
{
HuaffmanTreeNode*Root;//树根结点
Queuequ;//存放密码
public:
HuaffmanTree(void);
~HuaffmanTree(void);
voidSetRoot(HuaffmanTreeNode*p){this->Root=p;}
HuaffmanTreeNode*GetRoot(){returnRoot;}
HuaffmanTreeNode*Merge(HuaffmanTreeNode*pa,HuaffmanTreeNode*pb);//合并两个结点
voidCreateTree(LinkListL1);//创建哈夫曼树
int*GetCode(Typedata,LinkListL);//得到编码
voidCoding(LinkListL);//编码
voidDeCode(LinkListL);//译码函数
voidDisplay(HuaffmanTreeNode*p,intn);//遍历哈夫曼树
HuaffmanTreeNode*Find(Typedata,LinkListL);
voidGetCharFrenquency(LinkListL);//得到每种字符出现的次数
voidShowPriorText(LinkListL);
voidShowNodeBit(LinkListL);//输出每个结点的哈弗码编码
intGetHeight(HuaffmanTreeNode*p);//得到树的高度
};
3.程序的主要流程图
1
2
3
4
5
6
T
FF
4.程序的主要模块
#pragmaonce
#include"LinkList.h"
#include"Stack.h"
#include"Queue.h"
template//模板哈夫曼树类
classHuaffmanTree
{
HuaffmanTreeNode*Root;//树根结点
Queuequ;//存放密码
public:
HuaffmanTree(void);
~HuaffmanTree(void);
voidSetRoot(HuaffmanTreeNode*p){this->Root=p;}
HuaffmanTreeNode*GetRoot(){returnRoot;}
HuaffmanTreeNode*Merge(HuaffmanTreeNode*pa,HuaffmanTreeNode*pb);//合并两个结点
voidCreateTree(LinkListL1);//创建哈夫曼树
int*GetCode(Typedata,LinkListL);//得到编码
voidCoding(LinkListL);//编码
voidDeCode(LinkListL);//译码函数
voidDisplay(HuaffmanTreeNode*p,intn);//遍历哈夫曼树
HuaffmanTreeNode*Find(Typedata,LinkListL);
voidGetCharFrenquency(LinkListL);//得到每种字符出现的次数
voidShowPriorText(LinkListL);
voidShowNodeBit(LinkListL);//输出每个结点的哈弗码编码
intGetHeight(HuaffmanTreeNode*p);//得到树的高度
};
template
HuaffmanTree:
:
HuaffmanTree()
{
}
template
HuaffmanTree:
:
~HuaffmanTree()
{
this->Root=NULL;
}
template
HuaffmanTreeNode*HuaffmanTree:
:
Merge(HuaffmanTreeNode*pa,HuaffmanTreeNode*pb)
{
HuaffmanTreeNode*temp=newHuaffmanTreeNode();
if(pa->GetKey()GetKey())
{
temp->SetLchild(pa);
pa->SetTag(0);
temp->SetRchild(pb);
pb->SetTag
(1);
pa->SetFlag(true);
pb->SetFlag(true);
}
else
{
temp->SetLchild(pb);
pb->SetTag(0);
temp->SetRchild(pa);
pa->SetTag
(1);
pa->SetFlag(true);
pb->SetFlag(true);
}
temp->SetData('0');
temp->SetKey(pa->GetKey()+pb->GetKey());
pa->SetParent(temp);
pb->SetParent(temp);
returntemp;
}
template
voidHuaffmanTree:
:
CreateTree(LinkListL1)
{
HuaffmanTreeNode*pa,*pb;
pa=L1.GetHead()->GetNext();
pb=pa->GetNext();
while(pb)
{
HuaffmanTreeNode*temp=newHuaffmanTreeNode(pa->GetKey()+pb->GetKey(),'0',0);
pa->SetParent(temp);
pb->SetParent(temp);
if(pa->GetKey()>pb->GetKey())
{
temp->SetLchild(pb);
pb->SetTag(0);
pb->SetFlag(true);
temp->SetRchild(pa);
pa->SetTag
(1);
pa->SetFlag(true);
}
else
{
temp->SetLchild(pa);
pa->SetTag(0);
pa->SetFlag(true);
temp->SetRchild(pb);
pb->SetTag
(1);
pb->SetFlag(true);
}
L1.Insert(temp);
pa=pb->GetNext();
if(pa==NULL)
{
this->SetRoot(pb);
return;
}
pb=pa->GetNext();
if(!
pb)
{
this->SetRoot(pa);
return;
}
}
}
template
voidHuaffmanTree:
:
Display(HuaffmanTreeNode*p,intn)
{
if(p==NULL)
return;
this->Display(p->GetRchild(),n+1);
for(inti=0;icout<<'\t';
if(p->GetData()=='0')
cout<GetKey()<else
{cout<GetKey()<<"("<GetData()<<')'<this->Display(p->GetLchild(),n+1);
}
template
int*HuaffmanTree:
:
GetCode(Typedata,LinkListL)
{
Stacks;int*integer=newint[100];
HuaffmanTreeNode*current=L.GetHead()->GetNext();
while(current)
{
if(current->GetData()==data)
break;
current=current->GetNext();
}
if(current)
{
while(current->GetParent())
{
s.push(current->GetTag());
current=current->GetParent();
}
}
inti=0;
while(!
s.Empty())
{
qu.EnQueue(s.pop());
i++;
}
returninteger;
}
template
HuaffmanTreeNode*HuaffmanTree:
:
Find(Typedata,LinkListL)
{
HuaffmanTreeNode*current=L.GetHead()->GetNext();
while(current)
{
if(current->GetData()==data)
returncurrent;
current=current->GetNext();
}
returnNULL;
}
template
voidHuaffmanTree:
:
Coding(LinkListL)
{
qu.Clear();
inti=0;
while((L.List[i]<123&&L.List[i]>96)||L.List[i]==32)
{
GetCode(L.List[i],L);
i++;
}
}
template
voidHuaffmanTree:
:
DeCode(LinkListL)
{
inti=0;
while(!
qu.IsEmpty())
{
HuaffmanTreeNode*current=this->GetRoot();
while(current->GetData()=='0')
{
if(qu.DeQueue()==0)
current=current->GetLchild();
else
current=current->GetRchild();
}
cout<GetData();
}
}
template
voidHuaffmanTree:
:
GetCharFrenquency(LinkListL)
{
HuaffmanTreeNode*current=L.GetHead()->GetNext();
while(current)
{
if(current->GetData()!
='0')
{cout<GetData()<<""<GetKey()<current=current->GetNext();
}
}
template
voidHuaffmanTree:
:
ShowPriorText(LinkListL)
{
inti=0;
while((L.List[i]<123&&L.List[i]>96)||L.List[i]==32)
{
cout<i++;
}
}
template
voidHuaffmanTree:
:
ShowNodeBit(LinkListL)
{
HuaffmanTreeNode*current=L.GetHead()->GetNext();
while(current)
{
if(current->GetData()!
='0')
{cout<GetData()<<"";
GetCode(current->GetData(),L);
cout<current=current->GetNext();
}
}
template
intHuaffmanTree:
:
GetHeight(HuaffmanTreeNode*p)
{
if(!
p)return0;
inthl,hr;
hl=GetHeight(p->GetLchild());
hr=GetHeight(p->GetRchild());
returnhl>hr?
++hl:
++hr;
}
3.上机结果及体会
1.完成情况
该程序可以统计每种字符出现的次数,每个字符的哈夫曼编码,编码后的密文以及哈夫曼树,也可以将编码后的密文进行译文。
2.程序的运行结果
输入数据
按1进行的操作
按2进行的操作
按3进行的操作
哈夫曼树以旋转90度输出。
其中数字表示权值,括号里的字符表示元素的。
按4进行的操作
按5进行的操作
按6进行的操作
按0结束
3.程序可以改进及扩充的功能设计实现假想
改进:
将哈夫曼树以正常的树的形式输出
扩充:
可以将汉字进行编码
4.收获及体会
更加深入的理解数据的存储结构,能更好的利用数据的存储来增加空间的利用率.通过自己动手编写,将所学内容运用到实际中。
4.参考文献
《数据结构--C++实现》(修订版)缪淮扣、顾训穰、沈俊 编著
附录(源程序):
//主函数
#include"HuaffmanTree.h"
#include
usingnamespacestd;
intchoice;
voidMune(void)
{
cout<cout<<"1.显示字符的种类及每种字符出现的次数。
"<cout<<"2.输出原来的文本。
"<cout<<"3.输出Huffman树。
"<cout<<"4.得到每个结点的Huffman编码。
"<cout<<"5.输出整个文章的Huffman密文。
"<cout<<"6