《数据结构》课程设计.docx
《《数据结构》课程设计.docx》由会员分享,可在线阅读,更多相关《《数据结构》课程设计.docx(33页珍藏版)》请在冰豆网上搜索。
《数据结构》课程设计
沈阳工程学院
课程设计
课程设计题目:
数据结构与算法课程设计
系别信息工程学院班级物联本
学生姓名许学号2
指导教师职称讲师
任务下达时间:
2013年6月24日
起止日期:
2013年6月24日起——至2013年7月5日止
沈阳工程学院
课程设计任务书
设计题目:
写出图的广度优先搜索算法的非递归算法
哈夫曼编码
系别信息工程学院班级物21
学生姓名许学号2
指导教师职称讲师
任务下达时间:
2013年6月24日
起止日期:
2013年6月24日起——至2013年7月5日止
一、课程设计的原始资料及依据
数据结构与算法课程设计是在完成数据结构理论课程学习之后进行的一个综合性的实践教学环节,是对课程理论和课程实验的一个补充。
通过课程设计,培养学生综合运用已学过的理论和技能去分析和解决实际问题的能力,并使所学知识得到进一步巩固、深化和扩展。
二、课程设计主要内容及要求
设计内容:
1、写出图的广度优先搜索算法的非递归算法。
2、哈夫曼编码(※)
●问题描述:
利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
这就要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码。
对于双工信道(即可以双向传输信息的信道),每端都需要一个完成的编\译码系统。
试为这样的信息收发站写一个哈夫曼的编\译码系统。
●基本要求:
1.初始化。
从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树。
2.编码。
利用已建好的哈夫曼树,对正文进行编码。
3.译码。
对编码好的内容进行译码。
4.打印编码。
设计要求:
(1)每名同学任选三题;标※号的题为选做题,完成有加分;
(2)学生应明确设计任务和要求,并拟定设计计划,按时完成;
(3)设计分阶段进行,每一阶段的设计没有原则错误时才能允许进行下一阶段设计;
(4)设计过程中,提倡独立思考、深入钻研,主动地、创造性地进行设计;
(5)要求设计态度严肃认真、有错必改。
三、对课程设计说明书撰写内容、格式、字数的要求
1.课程设计说明书是体现和总结课程设计成果的载体,主要内容包括:
设计题目、设计目的、设备器材、设计原理及内容、设计步骤、遇到的问题及解决方法、设计总结、参考文献等。
一般不应少于3000字。
2.在适当位置配合相应的实验原理图、功能模块图、算法流程图等图表进行说明。
应做到文理通顺,内容正确完整,书写工整,装订整齐。
3.设计总结部分主要写本人完成工作简介以及自己的设计体会,包括通过课程设计学到了什么,哪里遇到了困难,解决的办法以及今后的目标。
4.课程设计说明书手写或打印均可。
手写要用学校统一的课程设计用纸,用黑或蓝黑墨水工整书写;打印时采用A4纸,页边距均为20mm,正文采用宋体小四号字,行间距18磅。
文中大标题采用黑体小三号字,一级节标题采用黑体四号字,二级节标题采用黑体小四号字,表题与图题采用宋体五号字。
5.课程设计说明书装订顺序为:
封面、任务书、成绩评定表、目录、正文、参考文献。
四、设计完成后应提交成果的种类、数量、质量等方面的要求
1.完成“任务书”中指定的功能,运行结果正确。
2.课程设计报告。
五、时间进度安排
顺序
阶段日期
计划完成内容
备注
1
第1天
阅读资料及系统分析设计
2
第2-5天
程序编制
3
第6-7天
程序调试
4
第8-9天
成绩评定
5
第10天
书写课程设计说明书
六、主要参考资料(文献)
[1]《数据结构》,清华大学出版社,2001,严蔚敏吴伟民
[2]《数据结构题集》,清华大学出版社,1999,严蔚敏吴伟民
[3]《数据结构习题与解析》,清华大学出版社,2006,李春葆
[4]《数据结构》,高等教育出版社,2006,许卓群
[5]《数据结构习题解析》,清华大学出版社,2011,殷人昆
沈阳工程学院
数据结构与算法课程设计成绩评定表
系(部):
信息工程学院班级:
物联本121学生姓名:
许荣燊
指导教师评审意见
评价内容
具体要求
权重
评分
加权分
调研
论证
能独立查阅文献,收集资料;能制定课程设计方案和日程安排。
0.1
5
4
3
2
工作能力
态度
工作态度认真,遵守纪律,出勤情况是否良好,能够独立完成设计工作,
0.2
5
4
3
2
工作量
按期圆满完成规定的设计任务,工作量饱满,难度适宜。
0.2
5
4
3
2
说明书的质量
说明书立论正确,论述充分,结论严谨合理,文字通顺,技术用语准确,符号统一,编号齐全,图表完备,书写工整规范。
0.5
5
4
3
2
指导教师评审成绩
(加权分合计乘以8)
分
加权分合计
指导教师签名:
年月日
评阅教师评审意见
评价内容
具体要求
权重
评分
加权分
查阅
文献
查阅文献有一定广泛性;有综合归纳资料的能力
0.2
5
4
3
2
工作量
工作量饱满,难度适中。
0.5
5
4
3
2
说明书的质量
说明书立论正确,论述充分,结论严谨合理,文字通顺,技术用语准确,符号统一,编号齐全,图表完备,书写工整规范。
0.3
5
4
3
2
评阅教师评审成绩
(加权分合计乘以4)
分
加权分合计
评阅教师签名:
年月日
摘要
“数据结构”是一门专业技术基础课。
它的教学要求是:
学会分析研究计算机加工的数据结构的特征,以便为应用涉及的数据选择适当的逻辑结构、存储结构及其相应的算法,并初步掌握算法的时间分析和空间分析的技术。
另一方面,本课程的学习过程也是复杂程序设计的训练过程,要求学生编写的程序结构清楚和正确易读,符合软件工程的规范。
图作为数据结构的重要一部分,它的应用十分广泛。
一方面由于很多实际问题跟图有关,例如通信线路、交通运输、集成电路布线图等;另一方面在于还有很多实际问题可间接地用图来表示,处理起来比较方便,例如工程进度的安排等。
图的遍历过程:
假设从图中的某个顶点V出发,在访问V之后依次访问V的各个未曾访问的邻接顶点,然后分别从这些邻接点出发依次访问他们的邻接点,并使“先访问的顶点的邻接点”先于“后访问的顶点的邻接点”被访问,直到图中所有已被访问的顶点的邻接点都被访问到。
哈夫曼的优点:
利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
创建赫夫曼树之后,从树根开始标志赫夫曼码,赫夫曼码是由0和1所组成的,左子树填入0,右子树填入1,因此欲知每一个数据元素的赫夫曼树的方法为:
对数据中出现过的每一个元素各自产生一树叶节点,并赋予树叶节点该元素的出现频率。
令L是所有树叶节点所成之集合:
产生一个新节点N
令N为L1和L2的父亲节点L1,L2和L2是L中出现频率最低的俩个节点。
令N节点的出现频率等于L1和L2的出现频率总和。
从L中删除L1和L2,并将N加入L中。
标志树中各个节点的左子树衔接为0,右子树衔接为1。
关键词:
广度,非递归,队列,树的构建,哈夫曼
第一章问题分析
1.1引言
图是比树更为复杂的一种非线性数据结构,在图结构中,每个节点都可以和其他任何节点相连接,图结构可以描述复杂的数据对象。
图有广泛的应用,一方面由于有很多实际问题与图有关,例如通信线路,交通线路,交通运输,集成电路布线图等;另一方面在于还有很多实际问题可以间接地用图来表示,处理起来比较方便,例如工程进度的安排等。
1.2背景
数据结构一般包括以下三方面内容:
数据的逻辑结构是从逻辑关系上描述数据,与数据的存储无关,是独立于计算机的。
数据的逻辑结构可以看作是从具体问题抽象出来的数学模型。
数据的存储结构是逻辑结构用计算机语言的实现,它依赖于计算机语言。
对机器语言而言,存储结构是具体的。
一般,只在高级语言的层次上讨论存储结构。
数据的运算定义在数据的逻辑结构上,每种逻辑结构都有一个运算的集合。
最常用的检索、插入、删除、更新、排序等运算实际上只是在抽象的数据上所施加的一系列抽象的操作。
所谓抽象的操作,是指我们只知道这些操作是"做什么",而无须考虑"如何做"。
只有确定了存储结构之后,才考虑如何具体实现这些运算。
1.3分析
图是一种复杂的非线形数据结构。
在图中数据元素之间的联系是任意的,即任何两个顶点都可能存在邻接关系。
图的存储方式主要有两种:
邻接矩阵和邻接表,我们在此次课程设计时候选择邻接表作为图的存储方式。
图的遍历就是从图的某一个顶点出发,访问图中每个顶点一次,切仅一次。
如果采用非递归算法就需要用到一个栈。
广度优先遍历是一种逐层横向搜索的过程。
不是递归过程,算法设计时候需要一个队列。
在无向图中,如果从顶点Vi到顶点Vj之间有路径,则称这两个顶点是连通的。
如过图中任意一对顶点都是连通的,则称此图为连通图。
本题目要求判断是否是连通图,根据邻接表的一些特性以及邻接表的概念。
设计一个简单的算法可以判断是否是连通图了。
第二章理论与运行环境
2.1数据理论
数据的逻辑结构可以看作是从具体问题抽象出来的数学模型。
数据的存储结构是逻辑结构用计算机语言的实现,它依赖于计算机语言。
对机器语言而言,存储结构是具体的。
一般,只在高级语言的层次上讨论存储结构。
数据的运算定义在数据的逻辑结构上,每种逻辑结构都有一个运算的集合。
最常用的检索、插入、删除、更新、排序等运算实际上只是在抽象的数据上所施加的一系列抽象的操作。
所谓抽象的操作,是指我们只知道这些操作是"做什么",而无须考虑"如何做"。
只有确定了存储结构之后,才考虑如何具体实现这些运算。
链表是一种有序的列表,链表的内容通常是存储与内存中分散的位置上。
链表的方式有两种:
一种是利用数组结构串连的有序列表。
例如;两个数组,一个存放数据,另一个存放连接的关系。
这种缺乏弹性。
另一种以动态内存配置的链表,(通常指的链表是一动态内存分配的链表)动态内存配置的链表,是由许许多多的(node)所链接而成的,每一个结点,包含了数据部分和指向下一个结点的指针(Pointer)。
以动态内存配置的链表,在插入和删除元素的时候,只需要将指针改变指向就可以。
链表和数组一样是一种数据结构,如何使用完全基于你的应用需求。
链表和C++语言本身没有任何联系。
很多语言都可以实现链表数据结构。
我讲一下数据和链表的区别有可能帮助你对链表的使用有个感觉。
数组是将元素在内存中连续存放,由于每个元素占用内存相同,所以你可以通过下标迅速访问数组中任何元素。
但是如果你要在数组中增加一个元素,你需要移动大量元素,在内存中空出一个元素的空间,然后将要增加的元素放在其中。
同样的道理,如果你想删除一个元素,你同样需要移动大量元素去填掉被移动的元素。
链表恰好相反,链表中的元素在内存中不是顺序存储的,而是通过存在元素中的指针联系到一起。
比如:
上一个元素有个指针指到下一个元素,以此类推,直到最后一个元素。
如果你要访问链表中一个元素,你需要从第一个元素开始,一直找到你需要的元素位置。
但是增加和删除一个元素对于链表数据结构就非常简单了,只要修改元素中的指针就可以了。
链表是指将若干个数据项按一定的规则连接起来的表,其中的数据项成为结点。
链表是一种常见的重要的数据结构。
它是动态地进行存储分配的一种结构。
它可以根据需要开辟内存单元。
链表有一个“头指针”变量,以head表示,它存放一个地址。
该地址指向一个元素。
链表中每一个元素称为“结点”,每个结点都应包括两个部分:
一为用户需要用的实际数据,二为下一个结点的地址。
因此,head指向第一个元素:
第一个元素又指向第二个元素;……,直到最后一个元素,该元素不再指向其它元素,它称为“表尾”,它的地址部分放一个“NULL”(表示“空地址”),链表到此结束。
2.2运行环境
VisualC++6.0的工作环境可以划分为三块区域,最左边的区域是工作区,最下面的区域是输出区,最右边的区域是编辑区。
编辑区用来对源文件进行编辑,现在的编辑区是灰色的,表示还没有源文件在进行编辑,输出区的作用是对程序进行编译和连接后,如果程序有错误或者警告,则显示在输出区,可以对照错误或者警告提示进行程序修改。
如下图:
VisualC++6.0的工作环境
图2.1VisualC++6.0的工作环境
第3章算法分析及实现
3.1程序流程图
1.广度优先遍历的流程图;
1.1主要流程图如下:
图3.1.1为广度优先遍历
1.2遍历实现:
3.1.2图的遍历实现
2.哈夫曼编码:
图3.2为哈夫曼遍历过程
3.2算法分析及设计
3.2.1创建图函数
voidcreate()
for(i=1;i<=e;i++)
{
printf("\npleaseinputtwovertexofaedge(s,d)\n");
scanf("%c,%c",&s,&d);
for(j=1;j{
if(s==g[j].data||d==g[j].data)
{
p=(structedgenode*)malloc(sizeof(structedgenode));
p->adjvex=d;
p->next=g[s].link;
g[s].link=p;
p=(structedgenode*)malloc(sizeof(structedgenode));
p->adjvex=s;
p->next=g[d].link;
g[d].link=p;
}
}
}
voidCreateMGraph(MGraph*G)//创建图
{
inti,j,k;
charch1,ch2;
printf("请输入顶点数和边数(输入格式为:
顶点数,边数):
\n");
scanf("%d,%d",&(G->n),&(G->e));
printf("请输入顶点信息(顶点号)每个顶点以回车作为结束:
\n");
for(i=0;in;i++)
{
getchar();
scanf("%c",&(G->vexs[i]));
}
for(i=0;in;i++)
for(j=0;jn;j++)
G->edges[i][j]=0;
printf("请输入每条边对应的两个顶点的序号(输入格式为:
i,j):
\n");
for(k=0;ke;k++)
{
getchar();
printf("请输入第%d条边的顶点序号:
",k+1);
scanf("%c,%c",&ch1,&ch2);
for(i=0;ch1!
=G->vexs[i];i++);
for(j=0;ch2!
=G->vexs[j];j++);
G->edges[i][j]=1;
for(i=0;ch1!
=G->vexs[i];i++);
for(j=0;ch2!
=G->vexs[j];j++);
G->edges[j][i]=1;
}
}
先选择要操作的部分创建图,然后依次输入顶点和边,图创建完成后按任意键结束,界面显示如图3.2.1
(1)所示:
3.2.1
(1)创建图函数界面
遍历图的非递归算法:
voidBFSTraverse(ALGraph*G,intv)/*从v出发遍历图G(非递归算法)*/
{
EdgeNode*p;intw,i;
intqueue[MAXV],front=0,rear=0;/*定义循环队列*/
boolvisited[MAXV];/*定义顶点的访问标志数组*/
for(i=0;in;i++)visited[i]=false;/*初始化*/
Visit(v);/*访问编号为v的顶点*/
visited[v]=true;/*置已访问标记*/
rear=(rear+1)%MAXV;/*已访点v入队*/
queue[rear]=v;
while(front!
=rear)/*若队列不空时循环*/
{
front=(front+1)%MAXV;
w=queue[front];/*已访顶点出队,赋给w*/
p=G->adjlist[w].firstedge;/*从w的首邻接点出发*/
while(p)/*找w的所有邻接点*/
{
if(visited[p->adjvex]==false)/*处理未访邻接点*/
{
Visit(p->adjvex);/*访问邻接点*/
visited[p->adjvex]=true;/*置已访标记*/
rear=(rear+1)%MAXV;/*已访点进队*/
queue[rear]=p->adjvex;
}
p=p->next;/*找下一个邻接点*/
}//while(p)
}//while(front!
=rear)
}
运行的结果为:
图3.2.1
(2)图的非递归遍历
3.2.2创建哈夫曼函数//实现哈夫曼编/译码
//------------------------主函数------------------------------------
voidmain()
{
charchoice;
while(choice!
='q')
{cout<<"\n******************************"<cout<<"欢迎使用哈夫曼编码解码系统"<cout<<"******************************"<cout<<"
(1)要初始化哈夫曼链表请输入'i'"<cout<<"
(2)要编码请输入'e'"<cout<<"(3)要译码请输入'd'"<cout<<"(4)要打印编码请输入'p'"<cout<<"(5)要打印哈夫曼树请输入't'"<cout<<"(6)要打印译码请输入'y'"<if(flag==0)cout<<"\n请先初始化哈夫曼链表,输入'i'"<cin>>choice;
switch(choice)
{
case'i':
Initialization();
break;
case'e':
Encoding();
break;
case'd':
Decoding();
break;
case'p':
Code_printing();
break;
case't':
Tree_printing(HT,2*n-1);
break;
case'y':
Code_printing1();
break;
default:
cout<<"inputerror"<}
}
free(z);
free(w);
free(HT);
}
如图运行如下:
图3.2.2
(1)哈夫曼树的创建
图3.2.2
(1)哈夫曼树的创建
//--------------初始化哈夫曼链表---------------------------------
voidInitialization()
{inta,k,flag,len;
a=0;
len=InputCode();
for(i=0;i{k=0;flag=1;
cou[i-a].data=str[i];
cou[i-a].count=1;
while(i>k)
{
if(str[i]==str[k])
{
a++;
flag=0;
}
k++;
if(flag==0)
break;
}
if(flag)
{
for(j=i+1;j{if(str[i]==str[j])
++cou[i-a].count;}
}
}
n=len-a;
for(i=0;i{cout<cout<}
for(i=0;i<=n;i++)
{*(z+i)=cou[i].data;
*(w+i)=cou[i].count;
}
HuffmanCoding(HT,HC,w,n);
遍历如下:
图3.2.2
(2)
图3.2.2
(2)初始化哈夫曼链表
建立哈夫曼的算法:
voidHuffmanCoding(HuffmanTree&HT,HuffmanCode&HC,int*w,intn)
{//w存放n个字符的权值(均>0),构造哈夫曼树HT,并求出n个字符的哈夫曼编码HC
intm,i,s1,s2,start;
//unsignedc,f;
intc,f;
HuffmanTreep;
char*cd;
if(n<=1)
return;//检测结点数是否可以构成树
m=2*n-1;
HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//0号单元未用
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)//建哈夫曼树
{
//在HT[1~i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2
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;