数据结构图实验总结(精选7篇)
本学期开设的《数据结构基础》课程已经告一段落,现就其知识点及其掌握情况、学习体会以及对该门课程的教学建议等方面进行学习总结。
各章知识点概要
第一章交代了该学科的相关概念,如数据、数据元素、数据类型以及数据结构的定义。其中,数据结构包括逻辑结构、存储结构和运算集合。逻辑结构分为四类:集合型、线性、树形和图形结构。紧接着介绍了一些常用的数据运算。最后着重介绍算法性能分析,包括算法的时间性能分析以及算法的空间性能分析。
第二章具体地介绍了线性表的概念、基本运算及其应用。基本运算有:初始化表、求表长、排序、元素的查找、插入及删除等。链表与顺序表相比,链表的插入、删除不需要移动元素,给算法的效率带来较大的提高。链表这一章中介绍了链表的节点结构、静态与动态链表的概念、链表的基本运算(如求表长、插入、查找、删除等)、单链表的建立(头插法和尾插法)、定义、结构、功能和基本算法。
第四章堆栈与队列是两种运算受限制的线性结构。其基本运算方法与顺序表和链表运算方法基本相同,不同的是堆栈须遵循“先进后出”的规则,对堆栈的操作只能在栈顶进行;而队列要遵循“先进先出”的规则,教材中列出了两种结构的相应算法,如入栈、出栈、入队、出队等。
第五章二叉树的知识是重点内容。在介绍有关概念时,提到了二叉树的性质以及两种特殊的二叉树:完全二叉树和满二叉树。接着介绍二叉树的顺序存储和链接存储以及生成算法。重点介绍二叉树的遍历算法:递归算法、先序、中序和后序遍历非递归算法。树与二叉树是不同的概念。教材介绍了树的概念、遍历和存储结构,还有树和二叉树的相互关系,树怎样转化成二叉树,二叉树又如何转换为树等。
第七章介绍了图的概念及其应用,是本书的难点。图的存储结构的知识点有:邻接矩阵、邻接表。图的遍历包括图的深度优先搜索遍历和广度优先搜索遍历。其余知识点有:有向图、连通图、最短路径问题。
学习体会和教学建议
这是一门纯属于设计的科目,它需用把理论变为上机调试。刚开始学的时候确实有很多地方我很不理解,每次上课时老师都会给我们出不同的设计题目,对于我们一个初学者来说,无疑是一个具大的挑战,撞了几次壁之后,我决定静下心来,仔细去写程序。老师会给我们需要编程的内容一些讲解,顺着老师的思路,来完成自己的设计,我们可以开始运行自己的程序。
这门课结束之后,我总结了学习中遇到的一些问题,最为突出的,书本上的知识与老师的讲解都比较容易理解,但是当自己采用刚学的知识点编写程序时却感到十分棘手,有时表现在想不到适合题意的算法,有时表现在算法想出来后,只能将书本上原有的程序段誊写到自己的程序中再加以必要的连接以完成程序的编写。
其实现在想起来,收获还真是不少,虽然说以前非常不懂这门语言,在它上面花费了好
多心血,觉得它很难,是需用花费了大量的时间编写出来的。现在真正的明白了一些代码的应用,每个程序都有一些共同点,通用的结构,相似的格式。只要努力去学习,就会灵活的去应用它。
建议在上课过程中加大随堂练习的分量,以便学生能当堂消化课堂上学习的知识,也便于及时了解学生对知识点的掌握情况,同时有助于学生保持良好的精神状态。
《数据结构》作为实践性很强的计算机专业的基础课, 教学中必然离不开实践。针对《数据结构》的课程设计实践不仅可以帮助学生巩固和加深对课程内容的理解, 更重要的是可以进一步锻炼程序设计的技能[1]。C语言是数据结构实验中重要的程序设计语言, 指针是C语言中一个非常重要的概念。在C语言中, 指针的应用非常灵活, 对于程序设计初学者来说比较难掌握, 更谈不上灵活合理的应用。《数据结构》中 (注:文中的讨论围绕严蔚敏老师的《数据结构》C语言版教材[2]) , 为了实现数据的存储结构, 指针在线性表、树和图的存储中都有重要的应用, 可以说, 数据结构的实验绕不开指针的应用, 如果学生掌握不好指针, 是无法进行数据结构实验学习的。
教学中注意到, 学生的主要问题是对指针的本质缺乏清晰的理解, 知其然不知其所以然, 导致在应用时只会依葫芦画瓢, 不会灵活应用。针对学生理解和应用中的难点问题, 剖析了指针的本质, 以此为基础, 讨论了指针的使用、指针和数组及指向函数的指针几个问题, 希望能够加深学生对指针的理解, 并在数据结构的实验中灵活应用。
二、指针
1. 变量和数据类型。
变量和数据类型是C语言中的基本概念, 是否能理解它们的本质, 对后续指针概念的理解非常重要。但是, 由于它们是最基本的东西, 教师和学生都认为很好理解, 不是很重视。因此, 学生对它们的理解往往流于表面, 产生模糊的认识, 如:变量是会变化的量;对变量名和变量的关系, 变量和数据类型的关系等认识不清。
对变量的理解应该强调变量最本质的意义:内存中的一块存储空间, 即所谓变量就是一块存储空间, 如图1所示。
围绕对变量本质的理解应该强调几点: (1) 一块空间 (变量) 具有两个特征, 一是这块空间在内存中的起始地址 (计算机内部16进制地址表示不便, 本文中用3位10进制数示意) , 表示这块空间的开始, 二是从起始地址开始的空间大小, 这两个特征一起确定了一个变量; (2) 作为内存的一块存储空间, 自然可以存储不同的值, 会变化; (3) 变量的声明是提出分配存储空间的要求, 没有分配空间, 当然不能存值, 不能使用; (4) 为了在程序中方便使用变量, 变量可以取一个名字, 即变量名。
变量都有数据类型, 从存储空间分配的角度看, 数据类型的本质是对分配空间大小的约定。要给一个变量分配存储空间, 涉及两个东西:分在那, 分多大。分在那由当前内存情况确定, 而分多大则由变量所属的数据类型确定, 如int型就分4个字节大小。
2. 指针的概念。
指针是C语言中的派生数据类型, 如int*p, 声明了一个由整型派生的指针变量p, 如图2所示。学生在为什么要用指针、指针变量和原类型之间是什么关系等问题上往往产生混淆, 不能够清晰理解。
对指针概念的理解应该强调几点: (1) 指针变量也是变量, 声明了指针变量后同样需要给该变量分配一块存储空间, 只是该空间存储的内容有点特殊, 是一个地址。 (2) 获取数据存储空间的基本方式有两种, 一是在程序的数据说明部分进行声明, 这样, 程序执行时存储空间已经预先分配, 并建立了变量名和存储空间之间的映射, 可称为静态分配。二是在程序执行的过程中, 通过申请 (如malloc函数) 获得存储空间, 可称为动态分配, 这样的空间无法给予变量名, 存取这样空间的唯一办法只能通过该空间的地址, 即指向该地址的指针来存取。如图2中圈1所示, malloc函数申请了一块大小为4个字节的空间, 空间起始地址是300, 为了在后续程序中使用这块存储空间, 该地址赋值给指向整型的指针p, p中存储的内容变为300。 (3) 应该强调, 作为派生类型, 指针变量也是有数据类型的, 其数据类型是指针变量所指向的存储空间大小的约定。如图2中定义的p是一个指向整型的指针, 强调这一点有助于学生对指针应用的理解。例如, 表达式中, 出现在指针变量前的*称为指针运算符, 如赋值语句*p=21, 其意义是给p中地址所指向的存储空间赋值, 图2中, p中存有地址300, 确定了被赋值空间的起始地址, 而p的类型-整型, 确定了这块空间的大小, 即*p确定了一块从300开始, 长度为4的存储空间。变量的本质是一块存储空间, 那么反过来说, 一块确定的存储空间就是一个变量, *p确定了一块存储空间, 它等价于变量, 给*p赋值等价于给整型变量赋值。
三、指针的应用
1. 指针和数组。
C语言中, 数组名代表数组的起始地址, 是一个常数, 可以看做一个指针。《数据结构》中, 线性表的顺序映像存储结构是通过动态申请的数组实现的, 设线性表为a1, a2, …, an (n=20) , 数据元素类型为整型, 其存储结构的定义如下所示:
上述代码主要定义了结构体数据类型Sqlist, 该结构体类型中包含3个域:elem, length和listsize, 其中elem是一个整型的指针变量, 用来指向申请存储空间的起始地址。类型定义后可以声明该类型的变量, 如Sqlist L;线性表的存储空间 (数组) 需要申请, 如图3所示。
malloc函数申请了一块大小为80个字节的存储空间, 该空间的起始地址假设为100, 函数返回后, 地址100被赋值给整型的指针变量L.elem, 即指针变量L.elem中存有地址100。
学生对静态数组的使用相对熟练些, 但往往不习惯动态申请数组的使用, 下面以线性表的遍历为例来说明一下其使用方式。动态申请数组中遍历的实现有两种常用方式:一是把指针当做数组名来使用。数组名是地址, 可以看做指针, 反之, 指针同样能够看做是数组名。遍历的代码可以写为:
这里要注意理解中括号[]的意义, 中括号本质上是运算符, 它的意义是执行操作L.elem+i (这里要关注指针的类型, 即不同类型的指针加i, 计算结果是不同的) , 找到存储ai+1这个整型数据的4个字节空间的起始地址, 随后根据指针的类型 (确定大小) , 存取这4个字节的存储空间。
二是通过指针来进行遍历。遍历的代码可以写为:
for (p=L.elem;p<L.elem+L.length;p++) {对数组元素*p进行处理}%%% (2)
整型指针p首先被赋值L.elem, 图3中是100, 这时p指向数组中第0号单元的起始地址, 通过指针运算符*p存取从100开始的4个字节空间, 即数组中第0号单元。随后, 通过p的自加运算, 指针p后移4个字节 (p是整型指针) , 依次对数组中所有元素进行遍历。从结果上来看, 代码 (1) 和代码 (2) 是完全等价的。
2. 链表。
线性表的非顺序映像存储结构是链表实现的。定义链表结点 (结构体) , 动态申请结点存储空间, 线性表每个数据元素存储在一个结点中, 通过指针描述数据元数之间的关系, 其结点的定义如下所示:
上述代码主要定义了结构体数据类型LNode和指向结构体的指针类型Link List, 该结构体类型中包含2个域:存储数据元素的域data和指针域next, next用来指向本结点数据元数在逻辑结构中的后继, 链表如图4所示。
仍以线性表的遍历为例来说明其使用方式, 利用指针p来进行遍历, 代码可以写为:
p被赋值p=head->next, 指向首元结点, 随后通过循环中p=p->next语句, p依次指向后继结点, 直到链表结束。这里要注意对->操作符的理解, 当指针p指向一个结构体存储空间时, 如果需要存取结构体中的某个域, 可以使用“p->域名”的方式, 如p->data就是存取该结构体中的data域;另有一种等价的方式“*p.域名”, 如*p.data, *p确定一块结构体空间 (结构体变量) , 用“.”操作符存取结构体变量的某个域。
3. 指向函数的指针。
函数载人内存时, 必定占有一块存储空间, 可以定义指向函数的指针, 通过指针来调用函数, 例如:
首先定义了一个指向函数的指针p, 随后p被赋值函数名, 即让p指向函数fun, p指向fun后, 可以通过指向函数的指针调用函数, 其效果和通过函数名调用是等价的。应该注意到, 这样用法毫无价值, 能通过函数名调用, 何必还要间接用指针调用。因此, 指向函数的指针一般用作函数的形式参数, 例如:
假设有数据元素为整型的二叉树T, Preorder是实现二叉树的先序遍历的函数。上述代码中, 首先给出了两个函数返回值为Status的函数原型, 设Sub是对整数进行减处理的函数, Add是进行加处理的函数。那么, Preorder (T, Sub) 调用时, 函数名Sub作为实参传递给形参visit (指向函数的指针) , 则在遍历过程中 (*visit) (a) 所调用的函数是Sub;同理, Preorder (T, Add) 调用时, (*visit) (a) 所调用的函数是Add。这里应该强调, 为什么要这么做?从上例中看, 对二叉树的遍历过程是一样的, 通过两次调用中visit所指的函数不同, 对二叉树T中数据元素的处理不同, 一次是减, 一次是加。指向函数的指针带来的好处是, 如果对数据元素的处理有新的变化, 如增加乘的处理, 仅需要编写乘的函数Mul, 随后调用Preorder (T, Mul) 就可实现对二叉树中数据元素的乘处理, 不需要改变Preorder函数。这样的程序结构非常有利于提高程序的可维护性。
四、小结
作为实践性很强的计算机专业核心课程, 《数据结构》课程的实验环节非常重要, 指针的灵活应用是课程实验中的难点。学生对指针了理解往往流于表面, 只会模仿性应用, 不能深入理解和灵活应用。文中, 我们结合实际的教学经验, 总结了指针中的几个学生不容易掌握的问题, 并分析讨论了教学中的要点。通过多年的教学实践, 对学生《数据结构》课程的学习和提高编程能力是有帮助的。
参考文献
[1]陈越, 何钦铭, 冯雁“.数据结构”综合性课程设计教学探索与实践[J].计算机教育, 2008, (8) :54-55.
关键词:数据结构实验教学
0引言
《数据结构》是计算机专业课程体系的核心课程之一。课程主要讲述各种数据的逻辑结构、物理结构及基本操作的实现算法以及数据查找、排序算法,并对各种算法进行性能分析和比较。
根据调查发现,目前大多数院校《数据结构》课程教学现状不容乐观。学生普遍反映课程学习比较困难,教师也感觉教学效果不理想。实验教学更是因为程序设计语言基础不扎实、课程内容太抽象等原因而较难开展,有些学校因此而缩短学时甚至不开设实验。一些专家和教师就课程实验教学改革已经提出了一些具体的教学方法,如案例驱动、课题答辩等。这些方法都具有比较重要的借鉴价值,但某些文章过于片面的强调某一种教学方法。笔者认为根据学生的实际情况完善教学设计、加强教学管理,通过行之有效的教学手段使学生学有所获才是根本。下面结合自己的实际教学工作,谈谈对数据结构实验教学方法的认识。我校《数据结构>课程理论学时48,实践学时16,教材选用严蔚敏的《数据结构(C语言版)》)。
1讲好理论第一课.明确课程性质
仅从课程名称来看,<数据结构》就很容易被误解为实践性不强的理论课。讲好第一堂理论课非常重要,应让学生明确课程性质并理解实践学习的重要性。
结合程序设计语言、操作系统等课程内容,笔者设计了一些学生比较熟悉并容易理解的应用实例和学生一起探讨。如:int a[10]和a[i]-5的确切含义;文件簇的链式形态;国际象棋大师与超级计算机的对决:图的着色问题等。在讲解图的着色问题时引导学生思考图的存储中需要关心什么,怎么存以及大致的程序逻辑等。通过对实例的分析,引入课程主要内容,学生也可明确课程的性质和专业地位并思考课程学习目标。
2制定实验教学计划.设计实验内容
程序设计语言是数据结构的前驱课程之一,多数院校都是以c语言程序设计作为学生程序逻辑训练的课程。数据结构教材中采用类C语言来描述算法,对指针、结构体等内容并未作详细的介绍。对于刚刚学完C语言的学生来说,指针等内容本来就比较模糊,要将类C算法转换为程序实现就更加困难。
在制定实验教学计划时,可以采用由易到难、逐步加深的方式来安排实验内容。结合实验学时数和教学大纲要求,笔者将实验内容作了如下设计和安排:
2.1第一次上机任务只要求学生运用以前学过的C语言知识来编写一个程序:给定一个整数序列,要求①用冒泡或选择算法进行排序:②输入一个整数x,在此有序序列中进行查找,如成功,则返回其位置;③如查找不成功,将×插入到序列中并使序列仍然有序。此题目运用到数组的定义、排序、查找、数组元素插入算法等相关内容。通过此实验,不仅能了解学生程序语言的熟悉程度,也能了解学生对排序和查找等基础算法的掌握情况,为后面教学内容设计作好铺垫。
2.2结合教学进度要求学生实现常见数据结构的基本操作,并能作一些验证性的实验。如用数字菜单的形式实现单向链表的基本操作,并完成两个有序链表合并算法的验证。实验要求学生能实现大多数基本操作算法,完成头文件的设计,并能利用已实现的基本操作完成复杂算法的验证。通过此类实验,学生对数据结构的理解更直观,程序逻辑更清晰,C语言的掌握能力逐渐增强,同时也为面向对象课程的学习打下一定的基础。
2.3设计性实验即课程设计安排。课程设计的目的在于培养学生分析和解决实际问题的能力,训练和提高学生规范的程序设计方法。教师可推出一些典型的并与后续课程有一定联系的题目供学生选择。每个题目规模不能太小,并能反映相关数据结构在程序设计中起的关键作用。如:①实现一个串的基本操作演示程序,提供命令行的输入(仿照COMMAND),并对命令行能进行简单的编译和出错处理,最后根据命令动词的功能来执行命令:②利用哈夫曼编码算法实现简单文本文件的压缩和解压。题目随着理论教学进度推出,有难有易,学生结合自己实际来选择并可提前完成。
3规范实验过程.加强实验教学管理
为保障划的有效实施,必须规范实验过程并加强实验教学管理。
3.1根据计划制定实验指导书。指导书中给出每个实验的目的、学时、内容等。其中设计性实验另给出一些基本的分析思路,每个实验都适当的添加一些选作题。学生通过阅读实验指导书能进一步明确每次实验的具体内容和要求。
3.2要求学生做好上机前的准备。大二学生的编码速度普遍较慢,如果把实验课时间主要用于输入代码是非常不值得的,应将主要精力放在程序调试上面。这样不仅有充足的提问时间,也便于教师归纳并集中讲解学生调试过程中所遇到的常见问题。
3.8要求学生实验后完成实验报告。报告中须给出问题分析、数据描述、算法描述、程序描述、测试结果和心得体会等内容。教师对学生提交的实验报告进行分析,总结并指出实验的成功和不足之处。
3.4加强实验教学管理,从正面引导学生。随着网络信息技术的发展,网络中提供的各种信息服务和娱乐方式使部分学生的学习积极性逐渐降低,学习目标也越来越不明确。如果管理松懈,有些学生就会把实践学习当成是简单的Ctrl-C和CtrI-V,不能达到实验教学的预期目标。因此,教师应了解学生的学习动态,加强实践教学管理,并根据实际情况进行相应调整和改进。
4丰富教学手段。搞好实验指导
在实践教学过程,教师不能只停留于解决学生提出的问题,还应不断摸索教学方法,丰富教学手段。
4.1演示基本算法实现时可采用互动的方式进行。先按类型定义一初始化一输入测试数据一输出的实现顺序和学生一起得到结果;再让学生逐个实现其余算法,最后完成头文件的设计。学生通过教师演示和实际操作可以更快的掌握类C算法和C程序的转换思路。
4.2数据结构中的程序规模相比C语言来说更大。由于缺乏经验,很多学生在程序调试中会出现较多的语法和逻辑错误,可利用多媒体网络教学手段在学生机上直接演示并讲解程序调试的方法和技巧。
4.8学生实验过程中尽力营造一种你追我赶的竞争氛围,通过激励机制提高学生学习积极性。如果有同学较早实现了某些算法,可有选择性的适当的“刺激”部分学生以激发其不服输的心理,从而带动其他学生。
4.4鼓励学生多实践,要求学生通过实践来找出理论学习中存在的问题,提高自己的抽象思维和逻辑推理能力。对于编程能力较强的学生,鼓励他们多做题,做难题,为今后参加各种资格水平考试和专业竞赛作好准备。
5总结
1.问题描述
为某个单位建立一个员工通讯录管理系统,可以方便地查询每一个员工的办公室电话号码、手机号码及电子邮箱。2.设计分析
在本设计中,整个通讯录可以采用顺序表或链表方式存储。其功能包括通讯录链表的建立、员工通讯信息的查询、修改、插入与删除以及整个通讯录表的输出。3.员工通讯信息的结构类型定义和通讯录链表的结点类型
typedef struct { char num[5];/*员工编号*/ char name[8];/*员工姓名*/ char phone[9];/*办公室电话号码*/ char call[12];/*手机号码*/ }DataType;/*员工通讯信息的结构类型*/ typedef struct node { DataType data;/*结点的数据域*/ struct node *next;/*结点的指针域*/ }ListNode,*LinkList;/*通讯录链表的结构类型*/ 4.实验源代码
// Address_List1.cpp : 定义控制台应用程序的入口点。// //#include “stdafx.h” #include“stdio.h” #include “stdlib.h” # include
char num[5];
/*员工编号*/
char name[8];
/*员工姓名*/ char phone[9];
/*办公室电话号码*/
char call[12];
/*手机号码*/
char mail[15];
/*邮箱*/ }DataType;/*通讯录单链表的结点类型*/ typedef struct node {
DataType data;
/*结点的数据域*/
struct node *next;
/*结点的指针域*/ }LNode, *LinkList;void CreateList(LinkList &L){//逆位序输入n个元素的值,建立带表头结点的单链线性表L
LinkList p;
int i,n;
L =(LinkList)malloc(sizeof(LNode));
L->next = NULL;
cout <<“请输入创建员工的通讯信息的个数:”;
cin >> n;
for(i = 0;i p =(LinkList)malloc(sizeof(LNode)); cout <<“ 请输入员工信息”< cout <<“ 员工编号:”; cin>> p->data.num; cout <<“ 员工姓名:”; cin >> p->data.name; cout <<“办公室电话号码:”; cin >> p->data.phone; cout <<“ 手机号码:”; cin >> p->data.phone; cout <<“ 员工邮箱:”; cin >> p->data.mail; cout <<“================================”<< endl; p->next = L->next; L->next = p; } } void InitList(LinkList &L){//初始化线性表 L =(LinkList)malloc(sizeof(LNode)); L->next = NULL;} void DestroyList(LinkList &L){//销毁线性表 LinkList p, q; p = L; q = p->next; while(q!= NULL) { free(p); } } int ListEmpty(LinkList &L){//判断线性表是否为空 if(L->next == NULL) return TRUE; else return FALSE;} int ListLength(LinkList &L){//求链表的长度 LinkList p = L; int c = 0; while(p->next!= NULL){ c++; p = p->next; } return(c);} void GetElem(LinkList &L){//取链表第i个数据元素 LinkList p = L->next; string s; cout <<“输入员工的编号或名字:”; cin >> s; while(p!= NULL)//根据相关信息,查找员工。 { if(p->data.num == s || p->data.name == s || p->data.phone == s || p->data.call == s || p->data.mail == s) break; p = p->next; } if(!p) cout <<“查无此人!”<< endl; else{ cout <<“ 员工信息”<< endl; cout <<“ 员工编号:”<< p->data.num << endl; cout <<“ 员工姓名:”<< p->data.name << endl; cout <<“办公室电话号码:”<< p->data.phone << endl; cout <<“ 手机号码:”<< p->data.phone << endl; cout <<“ 员工邮箱:”<< p->data.mail << endl; cout <<“================================”<< endl; } } void ReviseList(LinkList &L)//修改信息 { LinkList p = L->next; char j[20]; string s; int i; cout <<“输入员工的编号或名字:”; cin >> s; while(p!= NULL){//根据相关信息,查找员工。 if(p->data.num == s || p->data.name == s || p->data.phone == s || p->data.call == s || p->data.mail == s) break; p = p->next; } if(!p) cout <<“查无此人!”<< endl; else { cout <<“n想修改什么信息?_1-编号 2-姓名 3-办公室电话号码 4-手机号码 5-邮箱”<< endl; cin >> i; cout <<“想修改成什么?”<< endl; cin >> j; switch(i){ case 1:strcpy(p->data.num, j);break; case 2:strcpy(p->data.name, j);break; case 3:strcpy(p->data.phone, j);break; case 4:strcpy(p->data.call, j);break; case 5:strcpy(p->data.mail, j);break; default: cout <<“输入错误,”<< endl; system(“pause”); } cout <<“修改完毕!”; system(“pause”); return; } } void ListDelete(LinkList &L)//删除第i个元素 { LinkList p, q; int j = 0,i;p = L; cout <<“请输入你要删除第几个员工的信息:”; cin >> i; while(p->next && j < i1)//删除位置不合理 cout <<“删除位置不合理”<< endl; q = p->next; p->next = q->next;//删除并释放结点 free(q);} void ListInsert(LinkList &L){ LinkList s, p = L; s =(LinkList)malloc(sizeof(LNode)); cout <<“ 请输入员工信息”<< endl; cout <<“ 员工编号:”; cin >> s->data.num; cout <<“ 员工姓名:”; cin >> s->data.name; cout <<“办公室电话号码:”; cin >> s->data.phone; cout <<“ 手机号码:”; cin >> s->data.phone; cout <<“ 员工邮箱:”; cin >> s->data.mail; cout <<“================================”<< endl; s->next = p->next; p->next = s;} void PrintList(LinkList &L)//打印线性表 { LinkList p = L->next; int i = 1; if(p == NULL) cout <<“通讯录为空!”<< endl; while(p!= NULL) { cout <<“第 ”< cout <<“ 员工编号:”<< p->data.num << endl; cout <<“ 员工姓名:”<< p->data.name << endl; cout <<“办公室电话号码:”<< p->data.phone << endl; cout <<“ 手机号码:”<< p->data.phone << endl; cout <<“ 员工邮箱:”<< p->data.mail << endl; cout <<“==============================”<< endl; p = L; cout <<“请输入你要删除第几个员工的信息:”; cin >> i; while(p->next && j < i1)//删除位置不合理 cout <<“删除位置不合理”<< endl; q = p->next; p->next = q->next;//删除并释放结点 free(q);} void ListInsert(LinkList &L){ LinkList s, p = L; s =(LinkList)malloc(sizeof(LNode)); cout <<“ 请输入员工信息”<< endl; cout <<“ 员工编号:”; cin >> s->data.num; cout <<“ 员工姓名:”; cin >> s->data.name; cout <<“办公室电话号码:”; cin >> s->data.phone; cout <<“ 手机号码:”; cin >> s->data.phone; cout <<“ 员工邮箱:”; cin >> s->data.mail; cout <<“================================”<< endl; s->next = p->next; p->next = s;} void PrintList(LinkList &L)//打印线性表 { LinkList p = L->next; int i = 1; if(p == NULL) cout <<“通讯录为空!”<< endl; while(p!= NULL) { cout <<“第 ”< cout <<“ 员工编号:”<< p->data.num << endl; cout <<“ 员工姓名:”<< p->data.name << endl; cout <<“办公室电话号码:”<< p->data.phone << endl; cout <<“ 手机号码:”<< p->data.phone << endl; cout <<“ 员工邮箱:”<< p->data.mail << endl; cout <<“==============================”<< endl;break; case 4: //添加 ListInsert(L); cout <<“添加信息成功!”; system(“pause”); break; case 5: PrintList(L); ListDelete(L); cout <<“删除信息成功!”; system(“pause”); break;//输出全部信息 case 6: PrintList(L); system(“pause”); break; case 7: cout <<“该通讯录共有 ”<< ListLength(L)<<“ 员工信息!”<< endl;; system(“pause”); break; default: cout <<“输入错误!”<< endl; system(“pause”); } 实验题目: 输入十个数,从插入排序,快速排序,选择排序三类算法中各选一种编程实现。 实验所使用的数据结构内容及编程思路: 1.插入排序:直接插入排序的基本操作是,将一个记录到已排好序的有序表中,从而得到一个新的,记录增一得有序表。 一般情况下,第i趟直接插入排序的操作为:在含有i-1个记录的有序子序列r[1..i-1]中插入一个记录r[i]后,变成含有i个记录的有序子序列r[1..i];并且,和顺序查找类似,为了在查找插入位置的过程中避免数组下标出界,在 r[0]处设置哨兵。在自i-1起往前搜索的过程中,可以同时后移记录。整个排序过程为进行n-1趟插入,即:先将序列中的第一个记录看成是一个有序的子序列,然后从第2个记录起逐个进行插入,直至整个序列变成按关键字非递减有序序列为止。 2.快速排序:基本思想是,通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。 假设待排序的序列为{L.r[s],L.r[s+1],„L.r[t]},首先任意选取一个记录(通常可选第一个记录L.r[s])作为枢轴(或支点)(pivot),然后按下述原则重新排列其余记录:将所有关键字较它小的记录都安置在它的位置之前,将所有关键字较大的记录都安置在它的位置之后。由此可以该“枢轴”记录最后所罗的位置i作为界线,将序列{L.r[s],„,L.r[t]}分割成两个子序列{L.r[i+1],L.[i+2],„,L.r[t]}。这个过程称为一趟快速排序,或一次划分。 一趟快速排序的具体做法是:附设两个指针low和high,他们的初值分别为low和high,设枢轴记录的关键字为pivotkey,则首先从high所指位置起向前搜索找到第一个关键字小于pivotkey的记录和枢轴记录互相交换,然后从low所指位置起向后搜索,找到第一个关键字大于pivotkey的记录和枢轴记录互相 1 交换,重复这两不直至low=high为止。 具体实现上述算法是,每交换一对记录需进行3次记录移动(赋值)的操作。而实际上,在排列过程中对枢轴记录的赋值是多余的,因为只有在一趟排序结束时,即low=high的位置才是枢轴记录的最后位置。由此可以先将枢轴记录暂存在r[0]的位置上,排序过程中只作r[low]或r[high]的单向移动,直至一趟排序结束后再将枢轴记录移至正确位置上。 整个快速排序的过程可递归进行。若待排序列中只有一个记录,显然已有序,否则进行一趟快速排序后再分别对分割所得的两个子序列进行快速排序。 3.简单选择排序:其操作为,通过n-i次关键字间的比较,从n-i+1个记录中选出关键字最小的记录,并和第i(1≤i≤n)个记录交换之。 显然,对L.r[1„n]中的记录进行简单选择排序的算法为:令i从1至n-1,进行n-1趟选择操作。可以看出,简单选择排序过程中,所需进行记录移动的操作次数较少,其最小值为“0”,最大值为3(n-1)。然后,无论记录的初始排列如何,所需进行的关键字之间的比较次数相同,均为n(n-1)/2。 程序清单: 1.插入排序: #include for(i=1;i<=num.length;i++)printf(“%d ”,num.key[i]);} 测试用例: 输入:23 34 12 98 56 45 67 8 9 37 输出:charu:8 9 12 23 34 37 45 56 67 98 2快速排序: #include for(i=1;i<=num.length;i++)printf(“%d ”,num.key[i]);} 测试用例: 输入:23 34 12 98 56 45 67 8 9 37 输出:charu:8 9 12 23 34 37 45 56 67 98 3选择排序: #include intselectminkey(structsqlist *l,int a){ inti,j=a;for(i=a;i<=l->length;i++)if(l->key[i] for(i=1;i<=num.length;i++)printf(“%d ”,num.key[i]);} 测试用例: 输入:23 34 12 98 56 45 67 8 9 37 输出:charu:8 9 12 23 34 37 45 56 67 98 编程感想: 本次编程总共使用了三种排序方法,而这三种编程方法放在一起进行编写时,很容易就让我们对齐难易程度有了更深刻的了解。 首先,三种排序中,我们都像查表那样,设置了哨兵,而哨兵的使用可以减少对整个表的验空操作,使程序更加节省空间。 其次,对于插入排序,每次都要对一段序列进行检索,每排一次所要检索的序列长度减一,其时间发杂度为O(n^2)。 接着,对于快速排序,这个程序是比较复杂的,总共是3个函数,并且使用了递归的方法,这是但是,这种算法却是最优越的,平均性能也是最好的,我在编这个程序时,对其排序的思想有了进一步的了解,并努力拿他与冒泡排序进行比较,看出了些许其优越性。 还有,就是选择排序,简单选择排序思路简单,易于进行,但其时间发杂度与简单插入排序方法一样,都是O(n^2),性能不如快速排序。 迷宫问题实验报告 ——实验二 专业:物联网工程 班级:物联网1班 学号:15180118 姓名:刘沛航 一、实验目的 本程序是利用非递归的方法求出一条走出迷宫的路径,并将路径输出。首先由用户输入一组二维数组来组成迷宫,确认后程序自动运行,当迷宫有完整路径可以通过时,以0和1所组成的迷宫形式输出,标记所走过的路径结束程序;当迷宫无路径时,提示输入错误结束程序。 二、实验内容 用一个m*m长方阵表示迷宫,0和1分别表示迷宫中的通路和障碍。设计一个程序对于任意设定的迷宫,求出一条从入口到出口的通路,或得出没有通路的结论。 三、程序设计 1、概要设计 (1)设定栈的抽象数据类型定义 ADT Stack{ 数据对象:D={ai|ai属于CharSet,i=1、2…n,n>=0} 数据关系:R={|ai-1,ai属于D,i=2,3,…n} 基本操作: InitStack(&S) 操作结果:构造一个空栈 Push(&S,e) 初始条件:栈已经存在 操作结果:将e所指向的数据加入到栈s中 Pop(&S,&e) 初始条件:栈已经存在 操作结果:若栈不为空,用e返回栈顶元素,并删除栈顶元素 Getpop(&S,&e) 初始条件:栈已经存在 操作结果:若栈不为空,用e返回栈顶元 StackEmpty(&S) 初始条件:栈已经存在 操作结果:判断栈是否为空。若栈为空,返回1,否则返回0 Destroy(&S) 初始条件:栈已经存在 操作结果:销毁栈s }ADT Stack (2)设定迷宫的抽象数据类型定义 ADT yanshu{ 数据对象:D={ai,j|ai,j属于{‘ ’、‘*’、‘@’、‘#’},0<=i<=M,0<=j<=N} 数据关系:R={ROW,COL} ROW={|ai-1,j,ai,j属于D,i=1,2,…M,j=0,1,…N} COL={|ai,j-1,ai,j属于D,i=0,1,…M,j=1,2,…N} 基本操作: InitMaze(MazeType &maze, int a[][COL], int row, int col){ 初始条件:二维数组int a[][COL],已经存在,其中第1至第m-1行,每行自第1到第n-1列的元素已经值,并以值0表示障碍,值1表示通路。 操作结果:构造迷宫的整形数组,以空白表示通路,字符‘0’表示障碍 在迷宫四周加上一圈障碍 MazePath(&maze){ 初始条件:迷宫maze已被赋值 操作结果:若迷宫maze中存在一条通路,则按如下规定改变maze的状态;以字符‘*’表示路径上的位置。字符‘@’表示‘死胡同’;否则迷宫的状态不变 } PrintMaze(M){ 初始条件:迷宫M已存在 操作结果:以字符形式输出迷宫 } }ADTmaze (3)本程序包括三个模块 a、主程序模块 void main(){ 初始化; 构造迷宫; 迷宫求解; 迷宫输出; } b、栈模块——实现栈的抽象数据类型 c、迷宫模块——实现迷宫的抽象数据类型 2、详细设计 (1)坐标位置类型: typedef struct{ int row;//迷宫中的行 int col;//......的列 }PosType;//坐标 (2)迷宫类型: typedef struct{ int m,n;int arr[RANGE][RANGE];}MazeType;//迷宫类型 void InitMaze(MazeType &maze, int a[][COL], int row, int col)//设置迷宫的初值,包括边缘一圈的值 Bool MazePath(MazeType &maze,PosType start, PosType end)//求解迷宫maze中,从入口start到出口end的一条路径 //若存在,则返回true,否则返回false Void PrintMaze(MazeType maze)//将迷宫打印出来 (3)栈类型: typedef struct{ int step;//当前位置在路径上的“序号” PosType seat;//当前的坐标位置 DirectiveType di;//往下一个坐标位置的方向 }SElemType;//栈的元素类型 typedef struct{ SElemType *base;SElemType *top;int stacksize;}SqStack;栈的基本操作设置如下: Void InitStack(SqStack & S) //初始化,设S为空栈(S.top=NUL)Void DestroyStack(Stack &S)//销毁栈S,并释放空间 Void ClearStack(SqStack & S)//将栈S清空 Int StackLength(SqStack &S)//返回栈S的长度 Status StackEmpty(SqStack &S)?、若S为空栈(S.top==NULL),则返回TRUE,否则返回FALSE Statue GetTop(SqStack &S,SElemType e) //r若栈S不空,则以e待会栈顶元素并返回TRUE,否则返回FALSE Statue Pop(SqStack&S,SElemType e)//若分配空间成功,则在S的栈顶插入新的栈顶元素s并返回TRUE //否则栈不变,并返回FALSE Statue Push(SqStack&S,SElemType &e)//若分配空间程控,则删除栈顶并以e带回其值,则返回TRUE //否则返回FALSE Void StackTraverse(SqStack &S,Status)(*Visit)(SElemType e))//从栈顶依次对S中的每个节点调用函数Visit 4求迷宫路径的伪码算法: Status MazePath(MazeType &maze,PosType start, PosType end){ //求解迷宫maze中,从入口start到出口end的一条路径 InitStack(s);PosType curpos = start;int curstep = 1;//探索第一部 do{ if(Pass(maze,curpos)){ //如果当前位置可以通过,即是未曾走到的通道块 FootPrint(maze,curpos);//留下足迹 e = CreateSElem(curstep,curpos,1);//创建元素 Push(s,e);if(PosEquare(curpos,end))return TRUE;curpos =NextPos(curpos,1);//获得下一节点:当前位置的东邻 curstep++;//探索下一步 }else{ //当前位置不能通过 if(!StackEmpty(s)){ Pop(s,e);while(e.di==4 &&!StackEmpty(s)){ MarkPrint(maze,e.seat);Pop(s,e);//留下不能通过的标记,并退回步 } if(e.di<4){ e.di++;Push(s,e);//换一个方向探索 curpos = NextPos(e.seat,e.di);//设定当前位置是该方向上的相块 }//if }//if }//else }while(!StackEmpty(s));return FALSE;} //MazePath 四、程序调试分析 1.首先呢,想自己读入数据的,回来发现那样,很麻烦,所以还是事先定义一个迷宫。 2.栈的元素类型 一开始有点迷惑,后来就解决了 3.本题中三个主要算法;InitMaze,MazePath和PrintMaze的时间复杂度均为O(m*n)本题的空间复杂度也是O(m*n) 五、用户使用说明 1.本程序运行在windows系列的操作系统下,执行文件为:Maze_Test.exe。 六、程序运行结果 1.建立迷宫: 2.通过1功能建立8*8的迷宫后,通过2功能继续建立迷宫内部: 通过建立自己设定单元数目建立迷宫内墙。3.通过3功能观察已建立的迷宫结构: 4.通过4功能确立迷宫起点和终点: (此处像我们随机选择4,4和2,7分别为起点终点) 5.执行5功能,判断是否有路径走出迷宫: 这种情况无法走出迷宫。 我们再次观察图像设4,4和1,6分别为起点终点,再运行5功能。 观察到可以成功解开迷宫步数从1依次开始。 七、程序清单 #include // 列值 #define MAXLENGTH 25 // 设迷宫的最大行列为25 typedef int MazeType[MAXLENGTH][MAXLENGTH];// 迷宫数组[行][列] typedef struct // 栈的元素类型 { int ord;// 通道块在路径上的"序号" PosType seat;// 通道块在迷宫中的"坐标位置" int di;// 从此通道块走向下一通道块的"方向"(0~3表示东~北)}SElemType; // 全局变量 MazeType m;// 迷宫数组 int curstep=1;// 当前足迹,初值为1 #define STACK_INIT_SIZE 10 // 存储空间初始分配量 #define STACKINCREMENT 2 // 存储空间分配增量 // 栈的顺序存储表示 typedef struct SqStack { SElemType *base;// 在栈构造之前和销毁之后,base的值为NULL SElemType *top; int stacksize; // 构造一个空栈S int InitStack(SqStack *S){ // 为栈底分配一个指定大小的存储空间 (*S).base =(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));if(!(*S).base) (*S).top =(*S).base; return 1; // 栈底与栈顶相同表示一个空栈 (*S).stacksize = STACK_INIT_SIZE;exit(0);}SqStack;// 顺序栈 // 栈顶指针 // 当前已分配的存储空间,以元素为单位 } // 若栈S为空栈(栈顶与栈底相同的),则返回1,否则返回0。int StackEmpty(SqStack S){ if(S.top == S.base) else } // 插入元素e为新的栈顶元素。int Push(SqStack *S, SElemType e){ if((*S).top-(*S).base >=(*S).stacksize)// 栈满,追加存储空间 { } *((*S).top)++=e;return 1;} // 若栈不空,则删除S的栈顶元素,用e返回其值,并返回1;否则返回0。int Pop(SqStack *S,SElemType *e){ if((*S).top ==(*S).base) 左 return 1;} // 定义墙元素值为0,可通过路径为1,不能通过路径为-1,通过路径为足迹 // 当迷宫m的b点的序号为1(可通过路径),return 1;否则,return 0。int Pass(PosType b){ if(m[b.x][b.y]==1) else return 0;return 1;return 0;*e = *--(*S).top; // 这个等式的++ * 优先级相同,但是它们的运算方式,是自右向 (*S).base =(SElemType *)realloc((*S).base ,(*S).top =(*S).base+(*S).stacksize;(*S).stacksize += STACKINCREMENT;((*S).stacksize + STACKINCREMENT)* sizeof(SElemType));exit(0);if(!(*S).base)return 0;return 1;} void FootPrint(PosType a) // 使迷宫m的a点的序号变为足迹(curstep),表示经过 { m[a.x][a.y]=curstep;} // 根据当前位置及移动方向,返回下一位置 PosType NextPos(PosType c,int di){ PosType direc[4]={{0,1},{1,0},{0,-1},{-1,0}};// {行增量,列增量} // 移动方向,依次为东南西北 c.x+=direc[di].x;c.y+=direc[di].y;return c;} // 使迷宫m的b点的序号变为-1(不能通过的路径)void MarkPrint(PosType b){ m[b.x][b.y]=-1;} // 若迷宫maze中存在从入口start到出口end的通道,则求得一条 // 存放在栈中(从栈底到栈顶),并返回1;否则返回0 int MazePath(PosType start,PosType end){ SqStack S;PosType curpos;SElemType e; InitStack(&S);curpos=start;do { if(Pass(curpos)){// 当前位置可以通过,即是未曾走到过的通道块 FootPrint(curpos);// 留下足迹 e.ord=curstep;e.seat.x=curpos.x;e.seat.y=curpos.y;e.di=0;Push(&S,e);// 入栈当前位置及状态 curstep++;// 足迹加1 if(curpos.x==end.x&&curpos.y==end.y)// 到达终点(出口) } else return 1;curpos=NextPos(curpos,e.di);{// 当前位置不能通过 } if(!StackEmpty(S)){ } Pop(&S,&e);// 退栈到前一位置 curstep--;while(e.di==3&&!StackEmpty(S))// 前一位置处于最后一个方向(北){ } if(e.di<3)// 没到最后一个方向(北){ } e.di++;// 换下一个方向探索 Push(&S,e);curstep++;// 设定当前位置是该新方向上的相邻块 curpos=NextPos(e.seat,e.di); MarkPrint(e.seat);// 留下不能通过的标记(-1)Pop(&S,&e);// 退回一步 curstep--;}while(!StackEmpty(S));return 0;} // 输出迷宫的结构 void Print(int x,int y){ int i,j; for(i=0;i } } void main(){ PosType begin,end;int i,j,x,y,x1,y1,n,k;for(j=0;j //清屏函数 printf(“***************************************************nnn”);printf(“ 1请输入迷宫的行数,列数n”);printf(“ 2请输入迷宫内墙单元数n”);printf(“ 3迷宫结构如下n”);printf(“ 4输入迷宫的起点和终点n”);printf(“ 5输出结果n”);printf(“ 0退出n”);printf(“nn请选择 ”);scanf(“%d”,&n);switch(n){ case 1:{ printf(“请输入迷宫的行数,列数(包括外墙):(空格隔开)”); scanf(“%d%d”, &x, &y); for(j=1;j { for(i=1;i for(j=1;j // 迷宫左边列的周边即左边墙 m[j][y-1]=0;// 迷宫右边列的周边即右边墙 for(i=0;i // 迷宫上面行的周边即上边墙 m[x-1][i]=0;// 迷宫下面行的周边即下边墙 物 联 网 班 -15180118-刘沛 航 } }break; case 2: {printf(“请输入迷宫内墙单元数:”); scanf(“%d”,&j); printf(“请依次输入迷宫内墙每个单元的行数,列数:(空格隔开)n”); for(i=1;i<=j;i++) { scanf(“%d%d”,&x1,&y1); } m[x1][y1]=0; }break; case 3:{ Print(x,y);printf(“刘沛航建立的迷宫,定义墙元素值为0,可通过路径为1,输入0退出”);scanf(“%d”,&k);}break; case 4:{ printf(“请输入起点的行数,列数:(空格隔开)”); scanf(“%d%d”,&begin.x,&begin.y); printf(“请输入终点的行数,列数:(空格隔开)”); scanf(“%d%d”,&end.x,&end.y);}break; case 5:{ if(MazePath(begin,end))// 求得一条通路 { 1 非计算机专业实验教学的现状 (1)非计算机专业学生计算机语言基础较差,编程能力弱。“高级语言程序设计基础”是数据结构的前导课程之一。多数学校开设C语言作为前导课程,学生对C语言程序设计的掌握程度直接关系到数据结构课程的教学效果。而非计算机专业的学生一般在学习本课程之前并未经过严格的程序设计基础训练,对C语言理解不深,特别是指针、结构体和函数等知识点薄弱,难以在编程中灵活应用,但这些知识点在数据结构实验中应用频繁,导致学生上机实验效果差。 (2)实验课时少。由于实验时间和空间限制,学生在课内没有完成的实验无法在课外延续,使课堂上讲授的理论不能很好的巩固。 (3)课堂教学与实验教学相互脱节。数据结构是一门实践性很强的课程,教学中一定要理论与实践相结合,让学生从实践中加深对理论的理解,同时也让学生真正体会到理论是为实践服务的。但在目前的教学实践中,教师只注重学生课堂理论知识的掌握,降低了上机实验课的要求,学生实验课程的学习达不到理想的目标。 (4)实验项目单一,缺少创新性与自身专业相结合的实验项目。在数据结构实验项目的设置中,只注重了专业课程知识点的验证实验,而忽略了非计算机专业学生的设计性、创新性和与自身专业技术综合运用能力的培养。 (5)综合性实验完成较差。综合性实验最能体现学生知识点的掌握程度。要求学生利用所学的基本知识解决具体实际问题,培养学生分析问题、组织数据和解决问题的能力,有效地提高学生程序设计的能力。但在实际的实验教学过程中,只有极少数学生能完成实验的全部内容。 2 加强实验教学 数据结构是实践性很强的一门课,培养学生的实践能力是教学的首要目的。授课时引导学生利用上机实验来加强实践是教学中的一个重要环节。根据最优化教学模式,首先数据结构实验教学的目的是:紧密配合理论教学,通过相关实验,帮助和加深对数据的逻辑结构、存储结构、算法思想和具体实现等各个环节的整体理解;将各门课程学到的知识融会贯通,思考与发现利用数据结构解决实际应用问题的有效方法;强化学生“结构一算法一编程”三者密切相关的意识。平时的练习较偏重于如何编写功能单一的“小”算法,而实验是综合训练,包括问题分析、总体结构设计和程序设计的基本技能和技巧。围绕以上目标,非计算机专业《数据结构》的实验教学,同样遵循认知规律,逐步地从无到有,从观看演示到自己动手编程,从单一算法实现到综合设计分析,直到具体应用实例研究。其次,实验选题依据实验教学的目的,针对非计算机专业所要达到的实验教学目标,以及考虑学生的个体差异,将实验设置成必做和选做。前者目的在于帮助学生掌握基础知识和实验研究方法,后者则在于培养和鼓励学生的学习兴趣、扩大知识面以及培养学生的应用能力和创新意识。基于上述问题分析对非计算机专业的实验教学应该重点从以下几个方面考虑: 2.1 回顾C语言基础知识,提高C语言编程能力 在上机实验之前复习剖析C语言中的指针、结构体和函数等知识点。具体形式可以在课堂上以程序实例的形式对这些知识点进行复习,尤其指出学生难理解、容易混淆和犯错误的地方;布置涉及这些知识点的课外编程作业。通过作业批改发现问题后集体重点讲解;在实验教学中强调指针、结构体和函数等在数据结构课程中的重要性等。实验开始之前安排集中讲解,实验中教师现场辅导,实验课前、中、后组织交流讨论。对基本实验要求学生单独完成,一些综合实验则分组完成。 2.2 培养良好的程序编写习惯 非计算机专业的学生程序设计基础训练不足,数据结构上机实验的过程也是复杂程序设计的训练过程,程序除了能调试通过外,还要求学生编写的程序结构清晰、正确易读,符合软件工程的规范。良好的编程习惯需要在不断的实践中逐渐养成。因此,教师针对上述情况需要在以下几个方面重点培养学生良好的编程风格。 (1)良好的代码书写格式。采用良好的书写格式使代码可读性强,便于调试和交流。教师在实践过程中要强调和引导学生认识到书写格式的重要性,并逐步形成良好的代码格式书写习惯。 (2)良好的注释习惯。注释是程序的一个重要组成部分,可以使代码更容易理解。教师要强调注释的重要性,引导学生逐步养成良好的代码注释习惯。 (3)标识符合理命名。实践过程中教师要强调标识符命名规范的重要性,标识符命名要清晰、明了,有明确含义。 (4)重视实验报告的书写。实验报告除了常规内容外,需要重视实验中出现的问题、解决的办法、实验改进想法等内容的书写,这样可以培养学生实验后总结积累经验的习惯,提高学生分析、改进算法的能力。 2.3 兴趣是最好的老师 实验内容尽量选用贴近生活的一些例子,以激发学生的好奇心和兴趣。在介绍算法时注意补充一些算法的实际背景知识,可用于解决哪类问题,通过这种应用背景知识的介绍和来源于实际生活经验的联想来架设理论联系实际的桥梁,一方面可以维持学生的学习兴趣,增强学生学习的自主性;另一方面可以提高学生解决实际问题的能力。另外,通过编写多媒体教学课件和算法演示程序也可提高学生的兴趣。兴趣提上来了,课内未完成的实验,学生就会积极主动在课外完成。 2.4 抓住重点,提高实验效率 针对具体的教学内容教师给出相适应的上机实验内容。根据数据结构课程的特点,如顺序表、链表、二叉树、图等一些基础的上机实验中,要求学生完成后保留源程序,为其在后续的综合性扩展实验中省去了重复的编程和调试。利用这些实验的源程序所节省的时间,来完成综合性扩展实验。 2.5 注重实验题目的选择 实验题目尽量与专业相结合,注重综合应用能力的培养。问题的选择既注重选取那些数据结构课程中的经典题目,如汉诺塔问题、七桥问题和矩阵的压缩问题等,也设计了一些与学生专业紧密结合的新问题,如规划设计问题、交通路线咨询问题、图书查询和学生成绩统计等。实践证明,这大大提高了学生的学习热情和主动性,变较枯燥的验证性实验为设计性实验。引导学生利用更多的课外时间来完成实验题目,充分促进了学生间的讨论,提高了学生的实际动手能力。 2.6 提高团队意识,培养协作精神 综合性实验可以分小组完成,二到三人一组合作完成实验内容,要求同组学生在问题分析阶段和模块设计阶段分工合作、集体讨论、独立编写代码。最后每个学生都要进行面试,提交课程设计报告。学生必须能够清楚地介绍设计思路、主要技术手段并回答与题目相关的问题,并将程序进行现场演示。这样不但提高了学生分析问题、总体结构设计、程序设计的基本技能和技巧,也提高学生团队意识和协作精神。 3 结束语 非计算机专业要在相对较少的学时内部《数据机构》课程实验教学工作取得满意效果,是当前具有挑战性的课题。因此,合理、科学的实验教学过程,对于提高学生创新能力显得尤为重要。本文结合自身实验教学的经验,提出了一些实践证明行之有效的方法和原则,为非计算机专业的学生今后从事应用开发、技术管理工作培养了熟练的技能。 摘要:《数据结构》课程的理论教学很抽象,必须与实验教学紧密配合才能提高学生的实际应用能力。总结实验教学经验,提出实践证明行之有效的方法和原则,为非计算机专业实验教学水平的提高奠定了基础。 关键词:数据结构,实验教学,教学改革 参考文献 [1]严蔚敏,吴伟民.数据结构[M].北京:清华大学出版社,1997-04. [2]刘玉龙.数据结构与算法使用教程[M].北京:电子工业出版社,2007-02. 【数据结构图实验总结】推荐阅读: 《数据结构》实验报告——排序05-30 实验数据结构与算法06-23 数据结构实验线性表12-13 数据结构上机实验题02-15 北邮数据结构实验三04-16 数据结构实验3报告doc09-06 数据结构实验c语言版04-10 福州大学数据结构实验报告-线性表06-24 数据结构二叉树操作验证实验报告12-07 数据结构课程总结06-27《数据结构》实验报告——排序 篇5
数据结构迷宫问题实验报告 篇6
数据结构图实验总结 篇7