赫夫曼树数据结构课程设计.docx

上传人:b****8 文档编号:23758228 上传时间:2023-05-20 格式:DOCX 页数:17 大小:439.27KB
下载 相关 举报
赫夫曼树数据结构课程设计.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

赫夫曼树数据结构课程设计

赫夫曼树的建立

1.设计目的

本课程设计是为了配合《数据结构》课程的开设,通过设计一完整的程序,使学生掌握数据结构的应用、算法的编写、类C语言的算法转换成C程序并用TC上机调试的基本方法。

建立函数输入一个二叉树的结点个数及其所对应的权值,建立其对应的赫夫曼树,并输出其对应的赫夫曼编码。

通过设计程序,了解并掌握赫夫曼树的各种性质及其存储结构,学会赫夫曼编码的求解过程,并了解赫夫曼编码的广泛用途,掌握链表的灵活运用;学习链表初始化和建立一个新的单循环链表,并学会分析链表功能选择合适链表进行编程。

2.设计方案论证

2.1问题描述

赫夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。

所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。

树的带权路径长度记为WPL=(W1*L1+W2*L2+W3*L3+...+Wn*Ln),N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,...n)。

可以证明哈夫曼树的WPL是最小的。

2.2建立赫夫曼树的算法思想

(1)从n个权值{W1,W2,……,Wn}构造n棵只有一个结点的二叉树,其中每棵二叉树的左右子树均为空,从而得到n棵树的森林F={T1,T2,……,Tn}

(2)在森林F中,选出权值最小和次最小的二叉树分别作为左子树和右子树,构造一棵新的二叉树,且新二叉树根的权值为其左右子树上根结点的权值之和。

(3)在森林F中删除这两棵二叉树,同时把新的二叉树加入到森林F中。

(4)重复2和3两步骤,直到森林中只有一棵树为止,这棵树便是哈夫曼树。

2.3赫夫曼树的构造过程

下图展示了赫夫曼树的构造过程,其中根节点上标注的数字是所赋的权值。

图1赫夫曼树的构造过程

可以计算得到该赫夫曼树的路径长度:

WPL=(12+8)*3+2*15+1*17=107。

2.4赫夫曼编码求解过程

编写求赫夫曼编码操作就是按照建立赫夫曼树的算法思想建立一棵赫夫曼树,然后自底向上求得叶子结点(既每个字符)的赫夫曼编码。

步骤1:

以4个带权{7,2,5,4}字符为例,手动实现求解这4个字符的赫夫曼编码。

假设字符个数为n,则这棵赫夫曼树HT中结点个数为m,即m=2n-1=7。

按照算法思想

(1),其存储结构HT的初始状态如图2所示

图2HT初始状态图

步骤2:

按照算法思想步骤

(2)、(3)、(4),HT的终结状态如图3(a)所示(其中parent、lchild和rchild的值分别为结点在表中的序号)。

图3HT的终结状态图和树形

步骤3:

从叶子结点出发走一条从叶子结点到根路径便可求出每个字符的赫夫曼编码。

以求解值为2(结点序号为2)的结点的赫夫曼编码为例:

结点2是双亲结点5的左孩子,求得第一个编码为“0”;结点5是双亲结点6的右孩子,求得第二个编码为“1”

;结点6是双亲结点7的右孩子,求得第三个编码为“1”;结点7没有双亲,即结点7为根结点,整个赫夫曼编码求解完毕。

因为,求解过程是自底向上的过程,因此,权值为2的结点的赫夫曼编码为110(是求解过程顺序得到的编码逆序)。

最终得到的4个赫夫曼编码如图4所示

图44个字符的赫夫曼编码及树型

2.5算法设计

(1)主程序模块

voidmain()

{

初始化;

while(“命令”==“继续”)

{

接受命令;

处理命令;

}

}

(2)二叉树的存储结构表示

typedefstructBiTNode{

chardata;

intweigh;

structBiTNode*lchild,*rchild;

}BiTNode,*BiTree;

(3)赫夫曼树的存储结构和赫夫曼编码的存储结构

根据赫夫曼树的特点和操作特性,可以按图5所示的存储结构定义赫夫曼树。

图5赫夫曼树和赫夫曼编码的存储结构

具体算法描述如下:

typedefstruct

{

unsignedintweigh;//根结点的权值

unsignedintparent,lchild,rchild;//双亲、左孩子和右孩子的序号

}HTNode,*HuffmanTree;//动态分配数组存储赫夫曼树

Typedefchar**HuffmanCode;//动态分配数组存储赫夫曼编码表

(4)存储二叉树中的非空的权值非零的节点的结构

typedefstructtempsave{

intweigh;

charch;

}tempsave,*temp;

(5)最小权值的求解是在哈弗曼树中i个结点中找出权值最小的结点序号,相应的N-S图如图所示

图6查找i个结点中最小权值结点序号的N-S图

具体算法描述如下:

intmin(HuffmanTreet,inti)

 {//求解最小权值的操作

//初始条件:

赫夫曼树已存在

//操作结果:

返回i个结点中权值最小树的根结点序号,被select()调用

  intj,flag;

  unsignedintk=UINT_MAX;//取k为不小于可能的值

  for(j=1;j<=i;j++)

    if(t[j].weight

      {

k=t[j].weight;

flag=j;

}

  t[flag].parent=1;

  returnflag;

 }

 voidselect(HuffmanTreet,inti,int&s1,int&s2)//s1为最小的两个值中序号小的那个

 {

  intj;

  s1=min(t,i);

  s2=min(t,i);

  if(s1>s2)

  {

    j=s1;

    s1=s2;

    s2=j;

  }

 }

2.6程序设计思路

2.6.1功能模块图

各模块之间的调用关系如下:

图7功能模块图

2.6.2功能模块思路设计

(1)主程序模块

(2)二叉树创建模块:

实现二叉树的创建;从键盘建立二叉树采用先序遍历的顺序进行创建,并输入数据,由键盘输入每个节点的数据,当输入为“#”时,当前操作的节点指针为NULL,采用先左子树后右子树的顺序函数根据输入数据的形式,生成相应的二叉树结构。

(3)查找非零节点模块:

查找二叉树中非零节点,并存储其在一个数组中;

(4)哈夫曼树模块:

实现哈夫曼树的创建;

(5)输出模块:

输出创建的哈夫曼编码;

(6)查找最小叶节点模块:

查找非零叶节点中最小的两个。

系统流程图如下:

图8系统流程图

2.7程序源代码

#include

#include

#include

#include

#include

typedefstruct

{

  unsignedintweight;

  unsignedintparent,lchild,rchild;

 }HTNode,*HuffmanTree;//动态分配数组存储赫夫曼树

 

typedefchar**HuffmanCode;//动态分配数组存储赫夫曼编码表

intmin(HuffmanTreet,inti)

 {//求解最小权值的操作

//初始条件:

赫夫曼树已存在

//操作结果:

返回i个结点中权值最小树的根结点序号,被select()调用

  intj,flag;

  unsignedintk=UINT_MAX;//取k为不小于可能的值

  for(j=1;j<=i;j++)

    if(t[j].weight

      {

k=t[j].weight;

flag=j;

}

  t[flag].parent=1;

  returnflag;

 }

 voidselect(HuffmanTreet,inti,int&s1,int&s2)//s1为最小的两个值中序号小的那个

 {

  intj;

  s1=min(t,i);

  s2=min(t,i);

  if(s1>s2)

  {

    j=s1;

    s1=s2;

    s2=j;

  }

 }

voidHuffmanCoding(HuffmanTree&HT,HuffmanCode&HC,int*w,intn)

 {

intm,i,s1,s2,start;

unsignedc,f;

  HuffmanTreep;

  char*cd;

  if(n<=1)

    return;

  m=2*n-1;

  HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));

  for(p=HT+1,i=1;i<=n;++i,++p,++w)

  {

    (*p).weight=*w;

    (*p).parent=0;

    (*p).lchild=0;

    (*p).rchild=0;

  }

  for(;i<=m;++i,++p)

    (*p).parent=0;

  for(i=n+1;i<=m;++i)

  {

    select(HT,i-1,s1,s2);

    HT[s1].parent=HT[s2].parent=i;

    HT[i].lchild=s1;

    HT[i].rchild=s2;

    HT[i].weight=HT[s1].weight+HT[s2].weight;

  }

  //从叶子到根逆向求每个字符的哈夫曼编码

  HC=(HuffmanCode)malloc((n+1)*sizeof(char*));

  cd=(char*)malloc(n*sizeof(char));

  cd[n-1]='\0';

  for(i=1;i<=n;i++)

  {

    start=n-1;

    for(c=i,f=HT[i].parent;f!

=0;c=f,f=HT[f].parent)

      if(HT[f].lchild==c)

 cd[--start]='0';

      else

 cd[--start]='1';

    HC[i]=(char*)malloc((n-start)*sizeof(char));

    strcpy(HC[i],&cd[start]);

  }

free(cd);

 }

 voidmain()

 {

 printf("HuffmanTreeCreating&HuffmanEncoding,byss1271.\n");

 HuffmanTreeHT;

 HuffmanCodeHC;

   int*w,n,i;

   printf("请输入权值的个数(需要大于1):

");

   scanf("%d",&n);

   w=(int*)malloc(n*sizeof(int));

   printf("请依次输入%d个权值(整型,每输入完成一个请回车确认):

\n",n);

   for(i=0;i<=n-1;i++)

     scanf("%d",w+i);

   HuffmanCoding(HT,HC,w,n);

   printf("哈夫曼编码结果为:

\n");

   for(i=1;i<=n;i++)

     puts(HC[i]);

 }

3.运行结果分析

在本程序中,建立赫夫曼树需要用户输入节点的个数及其对应的权值,结点限定为大于0的整数,权值为不小于0的数。

输入节点个数后按空格键在输入权值(每输入一个权值键一下回车),再按回车键进行下一步输入。

演示程序以用户和计算机的对话方式执行,即在计算机终端上显示提示信息之后,由用户在键盘上输入程序要求的数据。

输入完毕后显示运算结果。

3.1运行结果及截图

(1)运行程序,提示输入权值的个数(即结点的个数,需大于1),运行结果如图9所示

 

图9提示输入权值个数

(2)输入结点个数后,击回车键,提示输入各个结点的权值,每输入一个权值后回车确认,知道提示下步操作,运行结果如图10所示

图10键入权值数量

(3)各个结点权值输入完毕后,回车确认,便会输出该树的赫夫曼编码,根据赫夫曼编码也可会出相应的赫夫曼树,运行结果如图11所示

图11输出赫夫曼树编码

3.2运行情况分析

(1)在输入一个空树的情况下,程序给出提示,若用户想继续则输入y后按回车键,否则输入n后回车。

(2)在输入树非空的情况下,程序会显示刚输入树的先序遍历结果,以及生成的赫夫曼树的先序遍历的结果。

其中每个节点组成为:

节点名(权值,左孩子节点名,右孩子节点名)。

(3)算法的时空分析

创建二叉树的算法createBiTree,查找非零节点的算法find以及打印赫夫曼树的算法print,都是遍历二叉树的操作。

显然遍历二叉树的算法中的基本操作是访问节点,则不论按哪一种次序进行遍历,对含n个节点的二叉树,其时间复杂度均为O(n).所需辅助空间为遍历过程中栈的最大容量,即树的深度,最坏情况下为n,则空间复杂读也为O(n)。

4.设计体会

这次设计我认为做的比较好的地方是清楚的将问题分为几个小的方面,用几个模块分别完成对应的功能,这样思路清晰,便于编写程序和调试。

这是一个值得保持的好习惯。

不好的一方面是对于生成的赫夫曼树缺乏一种简洁的表述,感觉自己的的表示方法有些繁琐。

如果能够用打印的方法输出生成的赫夫曼树就比较好。

通过本次课程设计,使我对赫夫曼树有了更深一步的了解。

在C语言的使用方面也有了一定的提高,对函数的调用上也有进步,比如开始我想用函数返回一个数组,但总是通不过编译,后来一查资料,才知道C中不能直接返回一个数组,于是我改用返回指向数组的指针,终于解决了问题。

同时,以前的模糊的概念也清晰了些。

比如以前以为只要想返回多个值,就可以用引用。

但在调试程序的时候发现并不是所有类型都有引用,比如数组就没有。

同时本程序还有一些不足之处,如初始化编码长时,在中途如果输入有误就得全部重输,这样非常不利于初始化很长的代码的输入,如果能够在出错时可以改正就好了。

这个实验题巩固和加深了我所学的知识,令我对以后的学习更加有兴趣。

我认为以后的实验题如果能够更贴近实际、贴进生活且难度适中就是最能激发学生学习兴趣的好实验题了。

通过这次试验我也着实感受了一次编程的乐趣,从中学到了不少的知识,更牢固的掌握了专业技能。

虽然都说“程序=数据结构+算法”,但我在学习运用数据结构编程之前,并没能深刻体会到这一点,直到这次课程设计实践才真正体会到了这一点。

以前使用C语言编程,只注重如何编写函数才能够完成所需要的功能,只凭单纯的意识和简单的语句来堆砌出一段程序。

但现在在编写一个程序之前,自己能够综合考虑各种因素,这样,即使在完整的程序还没写出来前,心里就已经有了明确的原图了,这样无形中提高了自己编写的程序的质量。

我还深刻的理解了数据结构的重要性,只有真正的理解这样定义数据类型的好处,才能用好这样一种数据结构,了解典型数据结构的性质非常有用的,它往往是编写程序的关键。

总之,这次课程设计巩固了我对所学知识的理解,加深了对编写程序的兴趣。

 

5.参考文献

[1]严蔚敏.数据结构C语言[M].北京:

清华大学出版社,2006.10:

118-144

[2]严蔚敏,陈文博.数据结构及应用算法教程[M].北京:

清华大学出版社,2003.6:

150-173

[3]吴艳,周苏,李益明等.数据结构与算法实验教程[M].北京:

科学出版社,2007.2:

169-174

[4]王立柱.c语言与数据结构[M].北京:

清华大学出版社,2005.5:

123-145

[5]谭浩强.c语言程序设计[M].北京:

清华大学出版社,1999.7:

137-158

[6]李春葆.数据结构(C语言篇)习题与解析[M].北京:

清华大学出版社,2000.2:

38-52

[7]严蔚敏,吴伟民.数据结构(C语言版)、数据结构题集[M].北京:

清华大学出版社,2005.7:

28-40

[8]夏克俭.数据结构+算法[M].北京:

国防工业出版社,2001.2:

264-271

[9]徐孝凯.数据结构实用教程(C描述).[M].北京:

清华大学出版社,2001304-305

 

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

当前位置:首页 > 工程科技 > 冶金矿山地质

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

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