您的位置:首页 > 理论基础 > 数据结构算法

哈夫曼编码译码(数据结构课程设计)

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”。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: