数据结构实验指导书.docx
《数据结构实验指导书.docx》由会员分享,可在线阅读,更多相关《数据结构实验指导书.docx(98页珍藏版)》请在冰豆网上搜索。
数据结构实验指导书
《数据结构》
实验指导书
主编:
郑兴旺
第一部分绪论
第一章概述
1.1实验目的
《数据结构》是一门实践性很强的软件基础课程,为了学好这门课,每个学生必须完成一定数量的上机作业。
通过本课程的上机作业,要求在数据结构的选择和应用、算法的设计及实现等方面加深对课程基础内容的理解,同时,在程序设计方法以及上机操作等基本技能和科学作风方面受到比较系统和严格的训练。
1.2实验要求
⒈问题分析
充分地分析和理解问题本身,弄清要求做什么,包括功能要求、性能要求、设计要求和约束以及基本数据特性,数据间的联系等。
⒉数据结构设计
针对要求解决的问题,考虑各种可能的数据结构,并且力求从中出最佳方案(必须连同算法一起考虑),确定主要的数据结构及全程变量。
对引入的每种数据结构和全程变量要详细说明其功能、初值和操作特点。
⒊算发设计
算法设计分概要设计和详细设计,概要设计着重解决程序的模块设计问题,这包括考虑如何把被开发的问题程序自顶向下分解成若干顺序模块,并决定模块的接口,即模块间的相互关系以及模块之间的信息交换问题.详细设计则要决定每个模块内部的具体算法,包括输入、处理和输出,相当于函数设计。
⒋测试用例设计
准备典型测试数据和测试方案,测试数据要有代表性、敏感性,测试方案包括模块测试和模块集成测试。
⒌上机调试
对程序进行编译,纠正程序中可能出现的语法错误,测试前,先运行一遍程序看看究竟将会发生什么,如果错误较多,则根据事先设计的测试方案并结合现场情况进行错误跟踪,包括打印执行路径或输出中间变量值等手段。
1.3实习报告内容
⒈问题描述:
包括目标、任务、条件和约束的描述。
⒉设计:
⑴数据结构设计和核心算法设计描述;
⑵主控及功能模块层次结构;
⑶主要功能模块的输入、处理(算法框架描述)和输出;
⑷功能模块之间的调用与被调用关系等。
⒊测试:
测试范例,测试结果,测试结果的分析与讨论,测试过程中遇到的主要问题及所采用的解决措施。
⒋使用说明和作业小结:
⑴使用说明主要描述如何使用你的程序以及使用时的主要事项;
⑵在小结中说明程序的改进思想、经验和体会,并回答教师布置的讨论题。
⒌打印一份程序清单及运行示例的结果。
将以上各项文字材料及程序清单等装订成册,形成一个完整的报告。
第二章
实验环境
为了更好的掌握数据结构和相关算法,对于结构和算法需要进行相应的程序实现。
选择使用Microsoft公司推出的VisualStudio系列产品中的VisualC++作为实现工具。
2.1VisualC++6.0简介
VisualC++6.0,简称VC或者VC6.0,是微软推出的一款C++编译器,将“高级语言”翻译为“机器语言(低级语言)”的程序。
VisualC++是一个功能强大的可视化软件开发工具。
自1993年Microsoft公司推出VisualC++1.0后,随着其新版本的不断问世,VisualC++已成为专业程序员进行软件开发的首选工具。
虽然微软公司推出了VisualC++.NET(VisualC++7.0),但它的应用有很大的局限性,只适用于Windows2000、WindowsXP和WindowsNT4.0。
所以实际的数据结构和C语言学习中,更多的是以VisualC++6.0为平台。
VisualC++6.0由Microsoft开发,它不仅是一个C++编译器,而且是一个基于Windows操作系统的可视化集成开发环境(integrateddevelopmentenvironment,IDE)。
VisualC++6.0由许多组件组成,包括编辑器、调试器以及程序向导AppWizard、类向导ClassWizard等开发工具。
这些组件通过一个名为DeveloperStudio的组件集成为和谐的开发环境。
Microsoft的主力软件产品。
VisualC++是一个功能强大的可视化软件开发工具。
自1993年Microsoft公司推出VisualC++1.0后,随着其新版本的不断问世,VisualC++已成为专业程序员进行软件开发的首选工具。
虽然微软公司推出了VisualC++.NET(VisualC++7.0),但它的应用的很大的局限性,只适用于Windows2000,WindowsXP和WindowsNT4.0。
所以实际中,更多的是以VisualC++6.0为平台。
VisualC++6.0以拥有“语法高亮”,自动编译功能以及高级除错功能而著称。
比如,它允许用户进行远程调试,单步执行等。
还有允许用户在调试期间重新编译被修改的代码,而不必重新启动正在调试的程序。
其编译及创建预编译头文件(stdafx.h)、最小重建功能及累加连结(link)著称。
这些特征明显缩短程序编辑、编译及连结的时间花费,在大型软件计划上尤其显著。
由于C++是由C语言发展起来的,也支持C语言的编译。
6.0版本是使用最多的版本,很经典。
最大的缺点是对于模版的支持比较差。
现在最新补丁为SP6,推荐安装,否则易出现编译时假死状态。
仅支持Windows操作系统。
目前发现与windows7兼容性不好,安装成功后可能会出现无法打开cpp文件的现象。
2.2集成开发环境介绍
VC6.0编程基本操作主要包括创建工程、编辑程序、编译程序、链接程序、运行程序、保存工程、打开工程和添加文件共8项操作。
创建工程:
选择"File|New"菜单项或直接按Ctrl+N快捷键,启动新建工程向导,选择Projects选项卡的列表框中的Win32ConsoleApplication选项,在Projectname文本框中添加工程名为"VCDemo"(或者你需要建立的工程名,该名称也是你要建立的应用程序的程序名),如图1.14所示。
从中可以看出,利用VC6.0可以创建17种Windows工程,分别如表1所示。
表1VC6.0的创建工程向导说明
工程向导
说明
ATLCOMAppWizard
创建ATLCOM组件向导
ClusterResourceTypeWizard
创建簇资源类型向导
CustomAppWizard
创建自定义AppWizard向导
DatabaseProject
直接创建数据库项目工程向导
DevStudioAdd-inWizard
创建自动化宏工程向导
ExtendedStoredProcWizard
创建扩展储存工程向导
ISAPIExtensionWizard
创建Internet服务器和过滤包工程向导
Makefile
创建编译链接的说明文件工程
MFCActiveXControlWizard
创建WindowsActiveX控件工程向导
MFCAppWizard(dll)
创建动态链接库工程向导
MFCAppWizard(exe)
创建一般Windows应用程序工程向导
NewDatabaseWizard
创建SQL服务器数据库工程向导
UtilityProject
创建简单实用的应用程序向导
Win32Application
创建Win32应用程序工程向导
Win32ConsoleApplication
创建Windows控制台程序向导
Win32Dynamic-LinkLibrary
创建Win32动态链接库工程向导
Win32StaticLibrary
创建Win32静态库工程向导
除了创建含有项目的工程之外,VC6.0还可以创建空白工程,在新建工程向导中单击Workspace选项卡,在Workspacename文本框中输入工程名即可,如图1所示。
空白工程里面没有任何文件,必须要程序员自己添加文件,包括.h文件、.cpp文件和资源文件等。
图1VC6.0创建工程向导
图2VC6.0创建空白工程向导
在工程向导对话框中单击OK按钮后,进入Win32ConsoleApplication对话框,如图1.16所示,选择"Anemptyproject."单选项,单击Finish按钮,进入NewProjectInformation对话框,它包含了该工程的一些基本信息,如图3所示。
图3Win32ConsoleApplication对话框
图4NewProjectInformation对话框
单击NewProjectInformation对话框中的OK按钮,这样就完成了项目的创建,并保存项目相关的信息。
项目的目录结构如图5所示。
在图中,VCDemo.dsw文件是项目工作区文件,双击此文件,即可打开此工程项目;VCDemo.dsp文件为项目文件。
添加文件:
为工程添加文件可以选择File菜单中的New命令,在新建向导中,单击Files选项卡,选择列表框中的C/C++SourceFile选项,并在File文本框中输入文件名"Demo1.c"(不写扩展名的话默认为cpp),如图6所示,然后单击OK按钮即可。
图5VCDemo工程项目的目录结构
图6为VCDemo工程添加文件
从中可以看出,利用VC6.0可以为工程添加13种类型的文件,分别如表2所示。
表2VC6.0为项目工程添加文件说明
文件类型
说明
ActiveServerPage
创建ASP页面
BinaryFile
创建二进制文件
BitmapFile
创建位图文件
C/C++HeaderFile
C/C++头文件(.h文件)
C++SourceFile
C++源文件(.cpp文件)
CursorFile
创建光标文件
HTMLPage
创建html文件
IconFile
创建图标文件
MacroFile
创建宏文件
ResourceScript
创建资源脚本文件
ResourceTemplate
创建资源模板文件
SQLScriptFile
创建SQL脚本文件
TextFile
创建文本文件
编辑程序:
双击VC主界面的工作区窗口的FileView选项卡,选择树形结构中的SourceFiles选项,双击Demo1.c文件,就可以在编辑窗口中编辑该头文件。
在Demo1.c文件中,添加代码如下:
#include
#include
voidmain()
{
printf("helloworld!
");
}
保存工程:
保存工程比较简单,选择File菜单中的SaveWorkspace命令即可。
如果项目由多个源程序构成,在保存工程时,需要保存相关的源程序。
可以通过选择File菜单中的Save命令(或者按下快捷键Ctrl+S)保存修改后的源程序。
编译程序:
选择Build菜单中的Compile命令,或直接按Ctrl+F7快捷键就可以直接对当前打开的源程序进行编译,编译结果如图7所示。
图7VCDemo工程的VCDemo.cpp文件编译结果
链接程序:
选择Build菜单中的Build命令,或直接按下快捷键F7就可以直接对当前项目进行链接,生成Windows应用程序,链接结果如图8所示。
图8VCDemo工程的链接结果
这样就完成了工程的链接过程,并生成了相关的应用程序信息。
生成的应用程序信息的文件默认情况下在工程目录debug目录下,生成的目录结构如图9所示。
图9VCDemo工程项目的链接信息目录结构
在上图中,vcdemo.exe是最后生成的可执行程序,demo1.obj是demo1.c源文件编译后生成的目标文件。
运行程序:
选择Build菜单中的Excute命令或直接按Ctrl+F5快捷键即可直接运行程序,程序运行结果如图10所示。
图10VCDemo程序运行结果
第二部分课内知识点程序设计
针对信息管理和电子商务专业的课程安排、学时安排和教学要求,对于上机实验部分按照以下章节进行课内知识点上机练习,其他部分以掌握算法思想和方法为主。
第三章线性表
线性表(LinearList):
由n(n≧)个数据元素(结点)a1,a2,…an组成的有限序列。
其中数据元素的个数n定义为表的长度。
当n=0时称为空表,常常将非空的线性表(n>0)记作:
(a1,a2,…an)
对于线性表结构,其实现上可以分为顺序实现和链表实现两种方式。
3.1线性表的顺序实现
把线性表的结点按逻辑顺序依次存放在一组地址连续的存储单元里。
用这种方法存储的线性表简称顺序表。
假设线性表的每个元素需占用l个存储单元,并以所占的第一个单元的存储地址作为数据元素的存储位置。
则线性表中第I+1个数据元素的存储位置LOC(ai+1)和第i个数据元素的存储位置LOCai)之间满足下列关系:
LOC(ai+1)=LOC(ai)+l
线性表的第i个数据元素ai的存储位置为:
LOCai)=LOC(a1)+(I-1)*l
3.1.1定义线性表结构体
按照下面给出的方法,建立新的Win32ConsoleApplication,并建立一个空工程。
然后选择新建c源文件,打开源文件后,在其中添加如下代码:
#include
#include
voidmain()
{
}
然后在头文件之后,main函数之前加入线性表结构体Seq的定义。
#include
#include
typedefstructseq
{
chardata[256];
intlength;
}Seq;
voidmain()
{
}
3.1.2线性表初始化
对于线性表,逻辑上可以进行初始化、输出、插入、删除、查找等操作。
依次实现,并在main函数中通过调用加以查验。
首先加入初始化函数,函数名定义为init,为了能在该函数中改变主函数中线性表的状态,需要将线性表的地址传递过来,该函数就需要接收一个Seq类型的指针作为形参。
#include
#include
typedefstructseq
{
chardata[256];
intlength;
}Seq;
voidinit(Seq*q)
{
q->length=0;
}
voidmain()
{
Seqs;
init(&s);
}
3.1.3插入操作
然后增加一个插入函数,该函数给定线性表、插入的位置和插入的字符。
建立函数
intinsert(Seq*q,charc,intpos),考虑到系统的健壮性,需要考虑空间满无法插入和输入位置不正确的情况。
首先处理异常情况。
intinsert(Seq*q,charc,intpos)
{
inti;
if(q->length>=256)
{
printf("空间满了\n");
return-1;
}
if(pos<1||pos>q->length+1)
{
printf("位置不存在\n");
return-2;
}
}
然后对于正常的插入情况,需要向后依次移动插入点后的元素,然后将待插入元素插入到制定位置,在程序中需要注意逻辑上的线性表位置和实际数组中下标位置的区别。
全部完成后的插入函数如下:
intinsert(Seq*q,charc,intpos)
{
inti;
if(q->length>=256)
{
printf("空间满了\n");
return-1;
}
if(pos<1||pos>q->length+1)
{
printf("位置不存在\n");
return-2;
}
for(i=q->length-1;i>=pos-1;i--)
q->data[i+1]=q->data[i];
q->data[pos-1]=c;
q->length++;
return0;
}
3.1.4输出函数
在此基础上,接着实现输出函数print,该函数需要将线性表作为参数传递过来,为了保持和其他函数的一致性,也采用将实参的地址传递过来,形参采用指针的形式。
voidprint(Seq*q)
{
inti;
for(i=0;ilength;i++)
{
if(i%10==0)
printf("\n");
printf("%c",q->data[i]);
}
}
3.1.5删除操作
接下来建立删除函数del,需要将所制定的线性表和需要删除的元素位置作为参数传递过来,与上面类似,也要注意异常情况的预先处理。
代码如下:
intdel(Seq*q,intpos)
{
inti;
if(pos<1||pos>q->length)
{
printf("位置不存在或线性表为空\n");
return-2;
}
for(i=pos;ilength;i++)
q->data[i-1]=q->data[i];
q->length--;
return0;
}
3.1.6查找操作
对于查找操作,可以分为根据位置查找元素和根据元素查找位置两种。
根据位置查找元素的代码如下:
charsearch2(Seq*q,intpos)
{
if(pos<1||pos>q->length)
return'#';
returnq->data[pos-1];
}
根据元素查找位置的代码如下:
intsearch1_1(Seq*q,charc)
{
inti=0;
for(i=0;ilength;i++)
if(q->data[i]==c)
returni+1;
returnq->length+1;
}
上述代码需要在每次循环时进行两次比较,分别是判断位置是否超出线性表大小,当前的值是否与待查找的值相等。
我们可以在此基础上进行改进,预先在最后一个元素的下一个位置放置一个待查元素,这样保证肯定能找到该元素。
返回位置后,如果返回的位置在线性表大小之外,说明查到的是预先放置的元素,实际上就是没有找到。
这样每次循环只需要进行一次比较了。
intsearch1(Seq*q,charc)
{
inti;
q->data[q->length]=c;
for(i=0;q->data[i]!
=c;i++)
;
returni+1;
}
3.1.7主函数及整个程序
最后需要在main函数中增加对上述函数的调用,整个代码如下所示(可以增加新的样例进行函数调用和测试):
#include
#include
typedefstructseq
{
chardata[256];
intlength;
}Seq;
voidinit(Seq*q)
{
q->length=0;
}
intinsert(Seq*q,charc,intpos)
{
inti;
if(q->length>=256)
{
printf("空间满了\n");
return-1;
}
if(pos<1||pos>q->length+1)
{
printf("位置不存在\n");
return-2;
}
for(i=q->length-1;i>=pos-1;i--)
q->data[i+1]=q->data[i];
q->data[pos-1]=c;
q->length++;
return0;
}
voidprint(Seq*q)
{
inti;
for(i=0;ilength;i++)
{
if(i%10==0)
printf("\n");
printf("%c",q->data[i]);
}
}
intdel(Seq*q,intpos)
{
inti;
if(pos<1||pos>q->length)
{
printf("位置不存在或线性表为空\n");
return-2;
}
for(i=pos;ilength;i++)
q->data[i-1]=q->data[i];
q->length--;
return0;
}
intsearch1_1(Seq*q,charc)
{
inti=0;
for(i=0;ilength;i++)
if(q->data[i]==c)
returni+1;
returnq->length+1;
}
intsearch1(Seq*q,charc)
{
inti;
q->data[q->length]=c;
for(i=0;q->data[i]!
=c;i++)
;
returni+1;
}
charsearch2(Seq*q,intpos)
{
if(pos<1||pos>q->length)
return'#';
returnq->data[pos-1];
}
voidmain()
{
intpos;
charc;
Seqs;
init(&s);
insert(&s,'B',1);
insert(&s,'F',2);
insert(&s,'C',3);
insert(&s,'E',4);
insert(&s,'X',2);
del(&s,4);
pos=search1(&s,'X');
c=search2(&s,2);
print(&s);
}
3.2线性表的链表实现
线性表的顺序表示的特点是用物理位置上的邻接关系来表示结点间的逻辑关系,这一特点使我们可以随机存取表中的任一结点,但它也使得插入和删除操作会移动大量的结点.为避免大量结点的移动,我们介绍线性表的另一种存储方式,链式存储结构,简称为链表(LinkedList)。
data
link
其中:
data域是数据域,用来存放结点的值。
next是指针域(亦称链域),用来存放结点的直接后继的地址(或位置)。
链表正是通过每个结点的链域将线性表的n个结点按其逻辑次序链接在一起的。
由于上述链表的每一个结点只有一个链域,故将这种链表称为单链表(SingleLinked)。
显然,单链表中每个结点的存储地址是存放在其前趋结点next域中,而开始结点无前趋,故应设头指针head指向开始结点。
同时,由于终端结点无后继,故终端结点的指针域为空,即null(图示中也可用^表示)。
3.2.1链表节点以及链表类型结构体定义
根据上述说明,建立链表节点。
为了保证对使用接口的一致性,再定义一个链表类型来封装链表节点,需要维护链表的表头节点的地址,以保证能依次访问到链表的其他节点。
结构体定义如下:
#include
typedefstructnode
{
chardata