数据结构 哈夫曼编码与译码Word文档下载推荐.docx
《数据结构 哈夫曼编码与译码Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《数据结构 哈夫曼编码与译码Word文档下载推荐.docx(15页珍藏版)》请在冰豆网上搜索。
资料查阅与讨论(1天)
系统分析(2天)
系统的开发与测试(5天)
编写课程设计说明书和验收(2天)
五、评分标准
1.根据平时上机考勤、表现和进度,教师将每天点名和检查
2.根据课程设计完成情况,必须有可运行的软件。
3.根据课程设计报告的质量,如有雷同,则所有雷同的所有人均判为不及格。
4.根据答辩的情况,应能够以清晰的思路和准确、简练的语言叙述自己的设计和回答教师的提问
六、建议参考资料
1.《数据结构(C语言版)》严蔚敏、吴伟民主编清华大学出版社2004.11
2.《数据结构课程设计案例精编(用C/C++描述)》,李建学等编著,清华大学出版社2007.2
3.《数据结构:
用面向对象方法与C++语言描述》,殷人昆主编,
清华大学出版社2007
目录
第一章需求分析4
第二章总体设计5
第三章抽象数据类型定义6
3.1LinkList抽象数据类型的设计6
3.2HuffmanTree抽象数据的设计6
第四章详细设计....................................................................................7
第五章测试8
第六章总结9
附录:
程序代码10
第一章需求分析
哈夫曼编码是一种编码方式,以哈夫曼树—即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩。
哈弗曼编码使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码。
这张编码表的特殊之处在于,它是根据每一个源字符出现的估算概率而建立起来的(出现概率高的字符使用较短的编码,反之出现概率低的则使用较长的编码,这便使编码之后的字符串的平均期望长度降低,从而达到无损压缩数据的目的)。
赫夫曼编码的应用很广泛,利用赫夫曼树求得的用于通信的二进制编码称为赫夫曼编码。
树中从根到每个叶子都有一条路径,对路径上的各分支约定:
指向左子树的分支表示“0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为和各个叶子对应的字符的编码,这就是赫夫曼编码。
哈弗曼译码输入字符串可以把它编译成二进制代码,输入二进制代码时可以编译成字符串。
第二章总体设计
(1)输入一个字符串用结构体链表存储字符串中出现的不同字符及其出现的次数。
(2)定义赫夫曼数的结点结构体,把不同的字符及其在字符串中出现的次数作为叶子结点的元素及其权值,统计叶子结点的个数n,开辟可以存储2*n个结点的顺序表,来赫夫曼树的各个结点,然后按照一定的规则构造赫夫曼树。
(3)开辟一个可以存储叶子结点元素及指向存储其赫夫曼编码链表的指针的顺序表,然后从叶子结点开始向上访问,是左孩子的把“0”接进链表是右孩子的把“1”接进链表,直到根结点,然后把叶子结点的元素及存储其赫夫曼链表的头指针读入顺序表,直到把所有的叶子结点的元素及指向存储其赫夫曼编码链表的头指针读入顺序表,这样得到的赫夫曼编码是倒序的。
(4)从存储其叶子结点及指向存储其赫夫曼编码链表头指针的顺序表表头开始顺序访问各元素,在输出其赫夫曼编码之前,把链表中的编码顺序读入到等长的栈中,然后编码出栈就会得到顺序的赫夫曼编码,直到把所有的叶子结点都访问到。
(5)用一个字符型的指针指向字符串的第一个字符,从存储叶子结点元素及指向存储其赫夫曼编码链表的头指针的顺序表表头开始访问顺序表中的各元素,直到找到叶子结点的元素和当前字符相等就结束访输出赫夫曼编码,直到输出字符串的最后一个字符的赫夫曼编码,这样就得到输入字符串的赫夫曼编码。
第三章抽象数据类型定义
3.1LinkList抽象数据类型的设计
ADTLinkList{
数据对象:
D={ai|ai∈ElemSet,i=1,2,…,n,n≥0}
数据关系:
R1={<
ai-1,ai>
|ai-1,ai∈D,i=2,…,n}
基本操作:
ListEmpty(L)
初始条件:
线性表L已存在。
操作结果:
若L表为空表,则返回TRUE,否则返回FALSE。
ListLength(L)
返回L中数据元素个数。
GetElem(L,i,&
e)
1≤i≤ListLength(L)。
用e返回L中第i个数据元素的值。
ListTraverse(L,visit())
依次对L的每个数据元素调用函数visit()。
一旦visit()失败,则操作失败。
}ADTLinkList
3.2HuffmanTree抽象数据的设计
typedefstruct{//赫夫曼树的结构体
charch;
intweight;
//权值
intparent,lchild,rchild;
}htnode,*hfmtree;
第四章详细设计
第五章测试
图表15.1
图5.1为哈夫曼编码与译码。
第六章总结
通过本次实验首先学习了霍夫曼树及其编码,接着分析写出了建立霍夫曼树和计算霍夫曼编码算法的代码,在huffman编码当中虽出现许多错误但通过了进一步的学习都可以学习改正,基本上可以实现Huffman编码算法的实现与编程应用。
两个星期的不懈努力,哈夫曼编译码系统课程设计顺利结束了,在这个过程中我收获了不少,同时也了解自己在某些方面做的还不够。
在此,感谢两星期来一直指导我们的班主任和那些为我解决设计过程中遇到的难题的同学们,谢谢大家!
今后我将继续努力,争取编出一套完整的哈夫曼编译码系统。
程序代码
#include<
iostream>
string>
//系统自带的字符串库函数
stdlib.h>
usingnamespacestd;
structNode
{chardata;
//节点数据域为字符型
Node*next;
Node(){next=NULL;
};
Node(charitem,Node*link=NULL){data=item;
next=link;
classLinkList
{//仅保留几个用得到的成员函数
protected:
Node*head;
Node*curPtr;
intcount,curPosition;
Node*GetElemPtr(intposition);
//返回指向第position个结点的指针
public:
LinkList();
intLength()const;
boolEmpty()const;
voidTraverse();
voidInsert(intposition,constchar&
e);
charGetElem(intposition);
Node*LinkList:
:
GetElemPtr(intposition)
{
if(curPosition>
position)
{curPosition=0;
curPtr=head;
}
for(;
curPosition<
position;
curPosition++)
curPtr=curPtr->
next;
returncurPtr;
}
charLinkList:
GetElem(intposition)
{Node*tmpPtr;
tmpPtr=GetElemPtr(position);
chare=tmpPtr->
data;
returne;
LinkList:
LinkList()
head=newNode;
//构造头指针,带表头结点的链表
curPosition=0;
count=0;
intLinkList:
Length()const
returncount;
boolLinkList:
Empty()const
returnhead->
next==NULL;
voidLinkList:
Traverse()
for(Node*tmpPtr=head->
tmpPtr!
=NULL;
tmpPtr=tmpPtr->
next)
{
cout<
<
(tmpPtr->
data);
Insert(intposition,constchar&
e)
tmpPtr=GetElemPtr(position-1);
Node*newPtr;
newPtr=newNode(e,tmpPtr->
next);
tmpPtr->
next=newPtr;
curPosition=position;
curPtr=newPtr;
count++;
//哈夫曼树结点类
structHuffmanTreeNode
unsignedintparent,leftChild,rightChild;
//双亲,左右孩子域
HuffmanTreeNode();
HuffmanTreeNode(intw,intp=0,intlChild=0,intrChild=0);
HuffmanTreeNode:
HuffmanTreeNode()
parent=leftChild=rightChild=0;
HuffmanTreeNode(intw,intp,intlChild,intrChild)//右孩子
weight=w;
//权
parent=p;
//双亲
leftChild=lChild;
//左孩子
rightChild=rChild;
//右孩子
classHuffmanTree
//
HuffmanTreeNode*nodes;
//存储结点信息,nodes[0]未用
char*LeafChars;
//叶结点字符信息,LeafChars[0]未用
string*LeafCharCodes;
//叶结点字符编码信息,LeafCharCodes[0]未用
intcurPos;
//译码时从根结点到叶结点路径的当前结点
intnum;
//叶结点个数
//辅助函数:
voidSelect(intcur,int&
r1,int&
r2);
//nodes[1~cur]中选择双亲为0,权值最小的两个结点r1,r2
voidCreatHuffmanTree(charch[],intw[],intn);
public:
HuffmanTree(charch[],intw[],intn);
//由字符,权值和字符个数构造哈夫曼树
virtual~HuffmanTree();
//析构函数
stringEncode(charch);
//编码
LinkListDecode(stringstrCode);
//译码
voidHuffmanTree:
Select(intcur,int&
r2)
r1=r2=0;
//0表示空结点
for(intpos=1;
pos<
=cur;
pos++)
if(nodes[pos].parent!
=0)continue;
//只处理双亲为0的结点
if(r1==0)
r1=pos;
elseif(r2==0)
r2=pos;
elseif(nodes[pos].weight<
nodes[r1].weight)
nodes[r2].weight)
CreatHuffmanTree(charch[],intw[],intn)
num=n;
intm=2*n-1;
//结点个数
nodes=newHuffmanTreeNode[m+1];
//nodes[0]未用
LeafChars=newchar[n+1];
//LeafChars[0]未用
LeafCharCodes=newstring[n+1];
//LeafCharCodes[0]未用
intpos;
//临时变量
for(pos=1;
=n;
{//存储叶结点信息
nodes[pos].weight=w[pos-1];
//权值
LeafChars[pos]=ch[pos-1];
//字符
for(pos=n+1;
=m;
{//建立哈夫曼树
intr1,r2;
Select(pos-1,r1,r2);
nodes[r1].parent=nodes[r2].parent=pos;
//r1,r2双亲为pos
nodes[pos].leftChild=r1;
//r1为pos的左孩子
nodes[pos].rightChild=r2;
//r2为pos的右孩子
nodes[pos].weight=nodes[r1].weight+nodes[r2].weight;
//pos的权为r1,r2的权值之和
{//求n个叶结点字符的编码
LinkListcharCode;
//暂存叶结点字符编码信息
for(unsignedintchild=pos,parent=nodes[child].parent;
parent!
=0;
child=parent,parent=nodes[child].parent)
{if(nodes[parent].leftChild==child)charCode.Insert(1,'
0'
);
elsecharCode.Insert(1,'
1'
;
for(inti=1;
i<
=charCode.Length();
i++)
LeafCharCodes[pos].append(1,charCode.GetElem(i));
//没有直接可以从链表为字符串赋值的函数,只能一个字符一个字符的追加过去
curPos=m;
HuffmanTree:
HuffmanTree(charch[],intw[],intn)
CreatHuffmanTree(ch,w,n);
~HuffmanTree()
if(nodes!
=NULL)delete[]nodes;
//释放结点信息
if(LeafChars!
=NULL)delete[]LeafChars;
//释放叶结点字符信息
if(LeafCharCodes!
=NULL)delete[]LeafCharCodes;
//释放叶结点字符编码信息
stringHuffmanTree:
Encode(charch)
=num;
{if(LeafChars[pos]==ch)returnLeafCharCodes[pos];
//找到字符,得到编码
LinkListHuffmanTree:
Decode(stringstrCode)
//操作结果:
对编码串strCode进行译码,返回编码前的字符序列
LinkListcharList;
//编码前的字符序列
for(intpos=0;
strCode.length();
{//处理每位编码
if(strCode[pos]=='
)curPos=nodes[curPos].leftChild;
//'
表示左分支
elsecurPos=nodes[curPos].rightChild;
if(nodes[curPos].leftChild==0&
&
nodes[curPos].rightChild==0)
{//译码时从根结点到叶结点路径的当前结点为叶结点
charList.Insert(charList.Length()+1,LeafChars[curPos]);
curPos=2*num-1;
returncharList;
intmain(void)
{char*ch;
int*w,n,i;
"
请输入字符集中字符的个数:
endl;
cin>
>
n;
ch=newchar[n];
w=newint[n];
请输入字符集中的字符:
for(i=0;
ch[i];
请输入字符集中的字符的权值:
w[i];
HuffmanTreehmTree(ch,w,n);
stringstrText,strCode;
请输入要编码的字符串"
strText;
cout<
"
文本串"
<
strText.c_str()<
编码为:
for(intpos1=0;
pos1<
strText.length();
pos1++)
stringstrTmp=hmTree.Encode(strText[pos1]);
strTmp.c_str();
endl;
intpos=0;
ch[i]<
的编码为:
stringstrTmp=hmTree.Encode(ch[pos]);
strTmp.c_str()<
pos++;
system("
PAUSE"
请输入要译码的二进制串"
strCode;
编码串"
strCode.c_str()<
译码为:
LinkListlkText=hmTree.Decode(strCode);
lkText.Traverse();
return0;