哈夫曼编码译码(数据结构课程设计)
2014-03-19 18:24
495 查看
1.需求分析
1.1问题描述
设计一个利用哈夫曼算法的编码和译码系统,重复地显示并处理以下项目,直到选择退出为止。1.2 基本要求
将权值数据存放在数据文件(文件名为data.txt,位于执行程序的当前目录中)分别采用动态和静态存储结构
初始化:键盘输入字符集大小n、n个字符和n个权值,建立哈夫曼树;
编码:利用建好的哈夫曼树生成哈夫曼编码;
输出编码;
设字符集及频度如下表:
字符 空格 A B C D E F G H I J K L M
频度 186 64 13 22 32 103 21 15 47 57 1 5 32 20
字符 N O P Q R S T U V W X Y Z
频度 57 63 15 1 48 51 80 23 8 18 1 16 1
1.3进一步完成内容
译码功能;显示哈夫曼树;
界面设计的优化。
2.概要设计
2.1存储结构设计
typedef struct HTNode{char c;
int weight;
int parent,lchild,rchild;
}HTNode,*HuffmanTree;
定义一个结构体表示哈夫曼树,结构体中包括输入的字符、该字符的权值,以及结点的双亲、左孩子、右孩子的下标变量。将哈夫曼树的各结点存储在由HuffmanTree定义的动态分配的数组中。
typedef char **HuffmanCode;
由于每个哈夫曼编码是变长编码,使用一个指针数组来存放每个字符编码串的首地址,各字符的哈夫曼编码存储在由HuffmanCode定义的动态分配的数组HC中,数组的0号单元不使用,从1号单元开始使用。
2.2功能算法设计
2.2.1构造哈夫曼树
将所有单元中的双亲、左孩子、右孩子的下标都初始化为0,再输入n个单元中叶子结点的字符、权值。通过n-1次的选择、删除与合并来创建哈夫曼树。选择功能另有函数说明,删除即将结点s1 和 s2 的双亲改为其下标值;合并即将s1 和 s2 的权值和作为一个新的权值依次存入到数组的第n+1 之后的单元中,同时记录这个新结点左孩子的下标为s1 ,右孩子的下标为s2。此模块的函数原型如下:void CreatHuffmanTree(HuffmanTree &HT, int n)
构造哈夫曼树的流程图如图一所示。
2.2.2选择权值最小的结点
从1~n数组中选择双亲为0且权值最小的两个树根结点s1 和 s2。此模块的函数原型如下:void Select(HuffmanTree HT,int i,int &s1,int &s2)
2.2.3生成哈夫曼编码
在构造哈夫曼树之后,依次以叶子为出发点,向上回溯至根结点为止。回溯时走左分支则生成代码0,走右分支则生成代码1。此模块的函数原型如下:void CreatHuffmanCode(HuffmanTree HT, HuffmanCode &HC, int n)
2.2.4编码
从终端输入一串字符串,将字符串中的字符依次与哈夫曼树中的字符进行比较,若相等,则输出相应的哈夫曼编码,若在哈夫曼树中找不到该字符,则提示输入字符有误。此模块的函数原型如下:void EnCoding(HuffmanTree HT,HuffmanCode HC,int n)
2.2.5译码
从终端输入一串0/1字符串,从哈夫曼树的根结点出发,若当前读入0,则走向左孩子,否则走向右孩子,直到HT[i]的左右孩子均为0,输出该数组单元的字符。然后重新从根结点出发继续译码,直到遇到字符串结束标志”\0”。 此模块的函数原型如下:void DeCoding(HuffmanTree HT,int n)
3.详细设计
3.1构造哈夫曼树
void CreatHuffmanTree(HuffmanTree &HT, int n)//creat a huffmantree which is HT
{
int s1 , s2;
if(n <= 1) return ;
int m = 2 * n - 1;
HT = new HTNode[m+1];
for(int i = 1;i <= m;++i) {
HT[i].parent = 0; HT[i].lchild = 0; HT[i].rchild = 0;
}
cout << "Enter the char and weight"<<endl;
for(int i = 1;i <= n;i++){
cin >>HT[i].c>> HT[i].weight;
}
for(int i = n+1;i <= m;++i) {
Select(HT,i-1,s1,s2);
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;
}
}
函数参数为指向哈夫曼树的指针的引用以及字符个数n,在此函数中初始化并创建哈夫曼树。
3.2选择权值最小的结点
void Select(HuffmanTree HT,int i,int &s1,int &s2) //Select sub-function{ int j,k=1; //s1 is the least of HT[].weight
while(HT[k].parent!=0) //s2 is the second least of HT[].weight
k++;
s1=k;
for(j=1;j<=i;++j)
if(HT[j].parent==0&&HT[j].weight<HT[s1].weight)
s1=j;
k=1;
while((HT[k].parent!=0||k==s1))
k++;
s2=k;
for(j=1;j<=i;++j)
if(HT[j].parent==0&&HT[j].weight<HT[s2].weight&&j!=s1)
s2=j;
}
在HT[k](1≤k≤i-1)中选择两个其双亲域为0且权值最小的结点,即依次与数组中的借点信息进行比较,找到最小权值的数组下标并返回其值。
3.3生成哈夫曼编码
void CreatHuffmanCode(HuffmanTree HT, HuffmanCode &HC, int n)// Create the HuffmanCode
{
int start,c,f;
HC = new char*[n+1];
char *cd = new char
;
cd[n-1] = '\0';
cout<<endl<<"HuffmanTree Code is as follows :"<<endl;
for (int i = 1;i <= n;i++){
start = n-1;
c = i; f = HT[i].parent;
while (f != 0){
--start;
if(HT[f].lchild == c) cd[start] = '0';
else cd[start] = '1';
c = f; f = HT[f].parent;
}
HC[i] = new char[n - start];
strcpy(HC[i],&cd[start]);
cout << HT[i].c;
cout << " 's Huffman code is: "<<HC[i]<<endl;
}
delete cd;
}
在构造哈夫曼树之后,依次以叶子为出发点,向上回溯至根结点为止。回溯时走左分支则生成代码0,走右分支则生成代码1。将生成的代码先从后往前依次存放在一个临时的一维数组cd中,并设一个变量start记录编码在cd中的起始位置(start初始时指示cd的结束位置)。当某字符编码完成时,从cd的start处将编码复制到该字符相应的编码串中。
3.4编码
void EnCoding(HuffmanTree HT,HuffmanCode HC,int n){
int len,i,j;
char str[1000];
cout << "Enter a string and decode it " << endl;
cin >> str;
len = strlen(str);
cout << "The relevant 0/1 numbers is :" << endl;
for(i = 0;i<len;i++){
for(j=1;j<=n;j++){
if(str[i] == HT[j].c)
cout << HC[j];
}
}
cout << endl;
}从终端输入一串字符串,将字符串中的字符HT[m]依次与哈夫曼树中的字符HC[i]进行比较,若相等,则输出相应的哈夫曼编码,若在哈夫曼树中找不到该字符,则提示输入字符有误。
3.5译码
void DeCoding(HuffmanTree HT,int n)// Enter a 0/1 string and decode it
{
int len,i,p;
int k1,k2;
char str[1000];
cout<<"Enter a seious of 01 code "<<endl;
cin>>str;
len = strlen(str);
cout << "The relevant chars is :" << endl;
for(i = 0;i<len;){
p = 2*n-1;
while(HT[p].lchild != 0 && HT[p].rchild != 0){
if(str[i] == '0') p = HT[p].lchild;
if(str[i] == '1') p = HT[p].rchild;
i++;
}
cout << HT[p].c;
}
cout << endl;
}
从终端输入一串0/1字符串,从哈夫曼树的根结点出发,若当前读入0,则走向左孩子,否则走向右孩子,直到HT[i]的左右孩子均为0,输出该数组单元的字符。然后重新从根结点出发继续译码,直到遇到字符串结束标志”\0”。
相关文章推荐
- 数据结构----dijkstra算法,单源最短路径
- C++代码,数据结构-内部排序-基数排序-链式基数排序
- 斐波那契数列算法分析
- 数据结构复习
- 数据结构-二叉搜所树java实现
- 数据结构--数据的读取
- 数据结构-完全hash,二级哈希java实现
- 数据结构学习笔记(6.顺序栈及链式栈)
- STL底层数据结构实现
- 数据结构--------二叉树的建立和前序遍历------递归实现
- 数据结构之队列的Java实现
- redis内部数据结构
- JSON入门级学习小结--JSON数据结构
- Reverse Words in a String
- oj之路(第三天)(续)
- Java之数据结构基础、线性表、栈和队列、数组和字符串,树—学习笔记
- 数据结构学习---队列
- 数据结构学习---栈
- 十五分钟介绍Redis数据结构
- 数据结构-用二维数组构造列表