哈夫曼树实验报告.docx

上传人:b****4 文档编号:3707071 上传时间:2022-11-24 格式:DOCX 页数:17 大小:54.91KB
下载 相关 举报
哈夫曼树实验报告.docx_第1页
第1页 / 共17页
哈夫曼树实验报告.docx_第2页
第2页 / 共17页
哈夫曼树实验报告.docx_第3页
第3页 / 共17页
哈夫曼树实验报告.docx_第4页
第4页 / 共17页
哈夫曼树实验报告.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

哈夫曼树实验报告.docx

《哈夫曼树实验报告.docx》由会员分享,可在线阅读,更多相关《哈夫曼树实验报告.docx(17页珍藏版)》请在冰豆网上搜索。

哈夫曼树实验报告.docx

哈夫曼树实验报告

数据结构实验报告

  实验名称:

实验三哈夫曼树

 学生姓名:

     班  级:

    班内序号:

     学 号:

  日 期:

程序分析:

2、1 存储结构:

二叉树

2、2程序流程:

template <classT>

classBiTree

public:

BiTree();ﻩﻩﻩﻩ//构造函数,其前序序列由键盘输入

 ~BiTree(void);ﻩﻩ//析构函数

ﻩBiNode

protected:

   BiNode*root;ﻩﻩﻩ//指向根结点得头指针

};

//声明类BiTree及定义结构BiNode

Data:

 二叉树就是由一个根结点与两棵互不相交得左右子树构成

 二叉树中得结点具有相同数据类型及层次关系

示意图:

 root

 lchild parent    rchild

   

哈夫曼树类得数据域,继承节点类型为int得二叉树

classHuffmanTree:

publicBiTree

data:

ﻩHCode*HCodeTable;//编码表

inttSize;//编码表中得总字符数

二叉树得节点结构

template

structBiNode      //二叉树得结点结构

{

Tdata;       //记录数据

Tlchild;//左孩子

ﻩT rchild;     //右孩子

ﻩTparent;  //双亲

};

示意图:

编码表得节点结构

structHCode

{

char data;   //编码表中得字符

char code[100];    //该字符对应得编码

};

示意图:

待编码字符串由键盘输入,输入时用链表存储,链表节点为

struct Node

{

ﻩcharcharacter; //输入得字符

ﻩunsignedintcount;//该字符得权值

ﻩbool used;  //建立树得时候该字符就是否使用过

ﻩNode*next;   //保存下一个节点得地址

charcharacter

unsignedintcount

boolused

Node*next

};

示意图:

2、3 关键算法分析:

 1、初始化函数(void HuffmanTree:

:

Init(stringInput))

算法伪代码:

1、初始化链表得头结点

2、获得输入字符串得第一个字符,并将其插入到链表尾部,n=1(n记录得就是链表中字符得个数)

3、从字符串第2个字符开始,逐个取出字符串中得字符

 3、1 将当前取出得字符与链表中已经存在得字符逐个比较,如果当前取出得字符与链表中已经存在得某个字符相同,则链表中该字符得权值加1。

 3、2 如果当前取出得字符与链表中已经存在得字符都不相同,则将其加入到链表尾部,同时n++

4、tSize=n(tSize记录链表中字符总数,即哈夫曼树中叶子节点总数)

5、创建哈夫曼树

6、销毁链表

 源代码:

  void HuffmanTree:

Init(stringInput)

{

   Node*front=newNode;  //初始化链表得头结点

if(!

front)

ﻩthrowexception("堆空间用尽");

front->next=NULL;

front->character=NULL;

front->count=0;

ﻩNode*pfront=front;

charch=Input[0]; //获得第一个字符

Node*New1=new Node;

ﻩif(!

New1)

ﻩ throwexception("堆空间用尽");

ﻩNew1->character=ch;   //将第一个字符插入链表

ﻩNew1->count=1;

ﻩNew1->next=pfront->next;

ﻩpfront->next=New1;

ﻩbool replace=0; //判断在已经写入链表得字符中就是否有与当前读出得字符相同得字符

int  n=1;     //统计链表中字符个数

for(inti=1;i

  ch=Input[i]; //获得第i个字符

  do

ﻩ{ﻩ

ﻩﻩpfront=pfront->next;

    if((int)pfront->character==(int)ch)//如果在链表中有与当前字符相同得字符,该字符权值加1

ﻩ{

ﻩpfront->count++;

ﻩﻩﻩreplace=1;

ﻩﻩbreak;

ﻩﻩﻩ}

ﻩ}while(pfront->next);

   if(!

replace)  //如果在链表中没找到与当前字符相同得字符,则将该字符作为新成

    员插入链表

{

ﻩﻩﻩNode*New=newNode;

ﻩﻩﻩif(!

New)

ﻩﻩthrowexception("堆空间用尽");

ﻩNew->character=ch;

ﻩﻩNew->count=1;

ﻩﻩNew->next=pfront->next;

ﻩﻩﻩpfront->next=New;

ﻩﻩn++;

ﻩ}

ﻩpfront=front;       //重置pfront与replace变量为默认值

ﻩreplace=0;

ﻩ}

tSize=n;    //tSize记录得就是编码表中字符个数

ﻩCreateHTree(front,n);   //创建哈夫曼树

ﻩpfront=front;

while(pfront)       //销毁整个链表

{

ﻩﻩfront=pfront;

ﻩpfront=pfront->next;

ﻩdeletefront;

}

  时间复杂度:

   若输入得字符串长度为n,则时间复杂度为O(n)

2、创建哈夫曼树(voidHuffmanTree:

:

CreateCodeTable(Node *p))

  算法伪代码:

1.创建一个长度为2*tSize-1得三叉链表

2.将存储字符及其权值得链表中得字符逐个写入三叉链表得前tSize个结点得data域,并将对应结点得孩子域与双亲域赋为空

3.从三叉链表得第tSize个结点开始,i=tSize

3.1从存储字符及其权值得链表中取出两个权值最小得结点x,y,记录其下标x,y。

3.2将下标为x与y得哈夫曼树得结点得双亲设置为第i个结点

3.3将下标为x得结点设置为i结点得左孩子,将下标为y得结点设置为i结点得右孩子,i结点得权值为x结点得权值加上y结点得权值,i结点得双亲设置为空

4、根据哈夫曼树创建编码表

源代码:

void HuffmanTree:

:

CreateHTree(Node*p,int n)

{

root=new BiNode[2*n-1];  //初始化哈夫曼树

ﻩNode *front=p->next;

if(n==0)

ﻩthrowexception("没有输入字符");

for(inti=0;i<n;i++)   //将n个字符得权值存储在哈夫曼树数组得前n位

{

ﻩroot[i]、data=front->count;

root[i]、lchild=-1;

ﻩroot[i]、rchild=-1;

ﻩroot[i]、parent=-1;

ﻩfront=front->next;

}

ﻩfront=p;

   intNew1,New2;

 for(i=n;i<2*n-1;i++)

    SelectMin(New1,New2,0,i);   //从0~i中选出两个权值最小得结点

root[New1]、parent=root[New2]、parent=i;//用两个权值最小得结点生成新结点,           新节点为其双亲

  root[i]、data=root[New1]、data+root[New2]、data;//新结点得权值为其孩子得权值得与

ﻩ root[i]、lchild=New1;

 root[i]、rchild=New2;

ﻩroot[i]、parent=-1;

}

ﻩCreateCodeTable(p);          //创建编码表

}

  时间复杂度:

    在选取两个权值最小得结点得函数中要遍历链表,时间复杂度为O(n),故该函数得时间复杂度为O(n^2)

3.创建编码表(voidHuffmanTree:

:

CreateCodeTable(Node*p))

   算法伪代码:

 1、初始化编码表

   2、初始化一个指针,从链表得头结点开始,遍历整个链表

    2、1将链表中指针当前所指得结点包含得字符写入编码表中

    2、2 得到该结点对应得哈夫曼树得叶子结点及其双亲

   2、3如果哈夫曼树只有一个叶子结点,将其字符对应编码设置为0

    2、4如果不止一个叶子结点,从当前叶子结点开始判断

2、4、1 如果当前叶子结点就是其双亲得左孩子,则其对应得编码为0,否则为1

2、4、2child指针指向叶子结点得双亲,parent指针指向child指针得双亲,重复2、4、1得操作

        2、5将已完成得编码倒序

   2、6取得链表中得下一个字符

    3.输出编码表

  源代码:

 voidHuffmanTree:

:

CreateCodeTable(Node*p)

{

  HCodeTable=newHCode[tSize];    //初始化编码表

Node*front=p->next;

for(inti=0;i

 {

ﻩﻩHCodeTable[i]、data=front->character; //将第i个字符写入编码表

ﻩintchild=i;       //得到第i个字符对应得叶子节点

ﻩ intparent=root[i]、parent;    //得到第i个字符对应得叶子节点得双亲

 intk=0;

ﻩ if(tSize==1)      //如果文本中只有一种字符,它得编码为0

{

ﻩﻩ HCodeTable[i]、code[k]='0';

ﻩk++;

}

ﻩwhile(parent!

=-1) //从第i个字符对应得叶子节点开始,寻找它到根结点得路径

ﻩ{

ﻩif(child==root[parent]、lchild) //如果当前结点为双亲得左孩子,则编码为0,        否则编码为1

     HCodeTable[i]、code[k]='0';

   else

      HCodeTable[i]、code[k]='1';

ﻩﻩk++;

  child=parent;

ﻩparent=root[child]、parent;

ﻩﻩ}

ﻩHCodeTable[i]、code[k]='\0';

 Reverse(HCodeTable[i]、code); //将编码逆置

ﻩ front=front->next;//得到下一个字符

ﻩ}

ﻩ cout<<"编码表为:

"<

 for(i=0;i<tSize;i++)     //输出编码表

ﻩ {

ﻩ cout<

}

}

  时间复杂度:

  需要遍历哈夫曼树获取编码,时间复杂度为O(n^2)

4.选择两个最小权值得函数

  算法伪代码:

1.从下标为begin得结点开始,寻找第一个没用过得结点

2.遍历哈夫曼树中从下标为begin到下标为end得结点序列,寻找没用过得同时权值又就是最小得结点。

3.暂时改变找到得权值最小结点得双亲域,防止第2次找到相同得结点。

4.将权值最小结点得下标记录下来。

5.重复步骤1~4,找到第2个权值最小得结点

源代码:

voidHuffmanTree:

SelectMin(int &New1,int&New2,int begin,intend)

{

intmin;

ﻩfor(intj=0;j<2;j++)   //要选择两个权值最小得结点

{

ﻩintsign=begin;

ﻩfor(int i=begin;i<end;i++)//从下标为begin得结点开始,寻找第1个没用过得结点

ﻩ{

ﻩ   if(root[i]、parent==-1)   //没用过得结点其双亲应为空

ﻩ{

ﻩ   min=root[i]、data;

ﻩﻩsign=i;

ﻩﻩﻩ   break;

ﻩﻩ}

ﻩﻩ}

for(i=begin;i<end;i++) //从begin到end,寻找权值最小得没用过得结点

ﻩﻩ{

   if(root[i]、parent==-1)

ﻩ{

ﻩﻩﻩﻩif(min>root[i]、data)

{

ﻩﻩmin=root[i]、data;

ﻩﻩsign=i;

ﻩﻩﻩ}

ﻩﻩ}

ﻩﻩ}

root[sign]、parent=0;//暂时改变所找最小结点得双亲域,防止第2次找到得就是同一个结点

ﻩif(!

j)

ﻩNew1=sign;

ﻩelse

ﻩﻩNew2=sign;

ﻩ}

}

  时间复杂度:

 两次遍历链表,时间复杂度为O(n)

5、将字符串倒序得函数(voidHuffmanTree:

:

Reverse(char*pch))

 算法伪代码:

1.得到字符串得长度

2.初始化两个记录下标得变量,一个为字符串开头字符所在得下标i,另一个为字符串结尾字符所在得下标j

3.将下标为i与j得字符交换

4.i++,j--

  时间复杂度:

  时间复杂度为O(n)

6、编码函数(void HuffmanTree:

:

Encode(string&s,string&d))

   算法伪代码:

    1、从s开头得字符开始,逐一对s中得字符进行编码

   2、在编码表中查找与当前字符对应得字符

 3.如果找到了与当前字符对应得编码表中得字符,将其编码追加到解码串得末尾。

      4、重复以上步骤,直到所有待编码串中得字符都编码完毕

5、输出编码后得字符串

源代码:

voidHuffmanTree:

:

Encode(string&s,string&d)

{

   for(intj=0;j

{

for(inti=0;i

ﻩ{

ﻩif(s[j] ==HCodeTable[i]、data)

ﻩﻩﻩ{

ﻩd、append(HCodeTable[i]、code);//编码

ﻩﻩﻩbreak;

ﻩﻩ}

ﻩ}

ﻩ}

cout<<d<

}

  时间复杂度:

设待编码字符串长度为n,编码表中字符个数为m,则复杂度为O(n*m)

7、解码函数

  算法伪代码:

1.得到指向哈夫曼树得根结点得指针与指向待解码串中得第1个字符得指针

2.逐个读取待解码串中得字符,若为0,则指向哈夫曼树当前结点得指针指向当前结点得左孩子,若为1,则指向当前结点得右孩子

3.指向待解码串得指针指向解码串中得下一个字符,直到指向哈夫曼树结点得指针得孩子结点为空

4.如果哈夫曼树只有一个叶子结点,直接将待解码串中得编码转换为对应得字符

5.如果指向哈夫曼树结点得指针得孩子结点已经为空,则将叶子结点下标对应得字符追加到解码串中。

6.输出解码串

      源代码:

    voidHuffmanTree:

:

Decode(string&s,string &d)

{

ﻩ for(inti=0;i<s、length();)

ﻩ{

   intparent=2*tSize-1-1;   //得到哈夫曼树得根结点

ﻩ  while(root[parent]、lchild!

=-1)    //如果结点不为叶子结点

ﻩ  {

ﻩﻩif(s[i]=='0')    //编码为0则寻找其左孩子

ﻩﻩ parent=root[parent]、lchild;

ﻩﻩ else   //编码为1则寻找右孩子

ﻩﻩ parent=root[parent]、rchild;

ﻩi++;

ﻩﻩ }

ﻩif(tSize==1)    //如果编码表只有一个字符,则根结点即为叶子结点

ﻩ  i++;

ﻩﻩ d、append(1,HCodeTable[parent]、data);//将叶子节点对应得字符追加到解码串中

cout<

}

  时间复杂度:

   设待解码串长度为n,则复杂度为O(n)

8、计算哈夫曼编码得压缩比(voidHuffmanTree:

:

Calculate(strings1,strings2))

  算法伪代码:

1.获得编码前字符串得长度,即其占用得字节数

2.获得编码后得字符串得长度,将其除以8然后向上取整,得到其占用得字节数

3.压缩比将两个相除

源代码:

    voidHuffmanTree:

:

Calculate(strings1,strings2)

{

intcal1=s1、length();      

 int cal2=s2、length();

ﻩcal2=ceill((float)cal2/8);    //将编码串得比特数转化为字节数

ﻩ cout<<"编码前得字符串长度:

"<

 cout<<"编码后得字符串长度:

"<<cal2<

 cout<<"压缩比为:

"<<((double)cal2/(double)cal1)*100<<"%"<

}

  时间复杂度:

 O

(1)

9、打印哈夫曼树(voidHuffmanTree:

PrintTree(intTreeNode,int layer) )

  算法伪代码:

1.如果待打印结点为空,则返回

2.递归调用函数打印当前结点得右子树

3.根据当前结点所在得层次确定其前面要输出多少空格,先输出空格,在打印当前结点得权值

4.递归调用函数打印当前结点得左子树

源代码:

void HuffmanTree:

:

PrintTree(intTreeNode,intlayer) 

{

  if(TreeNode==-1)        //如果待打印结点为空,则返回

ﻩﻩreturn;

else

{

PrintTree(root[TreeNode]、rchild,layer+1);//先打印该结点得右子树,layer记录得就是该结点所在得层次

for(inti=0;i

cout<<'';

cout<<root[TreeNode]、data<<endl;    //打印该结点得权值

PrintTree(root[TreeNode]、lchild,layer+1); //打印该结点得左子树

ﻩ}

}

    时间复杂度:

    中序遍历哈夫曼树,复杂度为O(n)

10、 菜单函数(voidHuffmanTree:

:

Menu())

   算法伪代码:

   1、逐一读取键盘缓存区中得字符,并将它们逐一追加到记录输入字符串得string变量中,直到读到回车输入符为止

    2、删除string变量末尾得回车输入符

  3.利用string变量创建哈夫曼树,初始化编码表。

    4、直观打印哈夫曼树

 5、 对输入得字符串进行编码

   6、 对编码后得字符串进行解码

   7、计算编码前后得压缩比并输出

    源代码:

    void HuffmanTree:

Menu()

{

cout<<"请输入您要编码得文本,按回车键确定输入"<

  stringInput;

char letter;

ﻩdo    //将字符逐个读入Input变量中

ﻩ{

letter=cin、get();

   Input、append(1,letter);ﻩ

ﻩ}while(letter!

='\n');

ﻩInput、erase(Input、length()-1,1); //去掉Input末尾得回车符

Init(Input);      //根据输入得字符串创建哈夫曼树及其编码表

ﻩcout<<"直观打印哈夫曼树"<

ﻩPrintTree(2*tSize-1-1,1);  //打印哈夫曼树

cout<<'\n'<<'\n';

stringd1,d2;

cout<<"编码后得字符串为"<

ﻩEncode(Input,d1);       //编码并打印编码串

ﻩcout<<"解码后得字符串为"<<endl;

ﻩDecode(d1,d2);    //解码并打印解码串

cout<<"ASCII码编码与HUFFMAN编码得比较"<<endl;

  Calculate(Input,d1);    //计算编码前后得压缩比

}

2、4 其她

 1、由于题目要求能输入任意长得字符串,所以本程序采用了string变量来记录输入得字符串,并采用string类得类成员函数来完成各项任务

  2、打印哈夫曼树时采用了递

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 职业教育 > 中职中专

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1