java项目——数据结构总结报告
20135315 宋宸宁
实验要求
1、用java语言实现数据结构中的线性表、哈希表、树、图、队列、堆栈、排序查找算法的类。
2、设计集合框架,使用泛型实现各类。
3、API的编写,并导出。
4、使用TDD模式,对程序进行测试,利用TestSuite将各测试类整合到一起。
5、与小组成员实现代码的整合。
实验设计过程
- 首先自学集合框架章节的内容,初步设计相关的类。
- 根据数据结构课本的章节分类,实验各数据结构类。
- 在类的编写过程中,经过老师的指导,我准备使用泛型这一新的功能。
- 将各数据结构类向上抽象,设计抽象函数和接口。例如,线性表中包括链表和顺序表,这两张表虽然是不同的数据结构,但是有很多相同的地方,比如判断表是否为空、删除、插入等操作都是两者共有的,所以可以抽取出来,作为线性表的接口。
- 将不同的数据结构放在不同的包中,这样以便使用。
- 在编写代码的过程中,注意帮助文档和TDD测试的跟进编写。
实验内容
1、线性表的编写
首先根据线性表的性质,进行功能的抽取,设计list接口,让顺序表类和链表类分别实现它的功能,具体包括isEmpty()是否为空函数,insert()插入函数,append()尾插函数,search()查找函数,remove()删除函数,get()获取元素函数,set()重置函数,length()长度函数等。
然后依次在顺序表中实现以上函数,在实现接口的同时,增加特殊性的函数,如构造函数等。
在链表中实现以上类,注意,在链表类的设计中,要先设计出链表节点类,以便在链表的构造函数中调用。链表节点类中并没有具体方法,只有3种不同的构造函数方法。
2、队列堆栈的编写
首先根据队列的性质,进行功能的抽取,设计queue接口,具体包括isEmpty()是否为空函数,enqueue()入队函数,dequeue()出队函数等。
然后依次用数组类型实现顺序队列,用链表类型实现链表队列。
首先根据堆栈的性质,进行功能的抽取,设计stack接口,具体包括isEmpty()是否为空函数,push()入栈函数,pop()出栈函数,get()获取函数等。
然后依次用数组类型实现顺序堆栈,用链表类型实现链表堆栈。
3、图的编写
首先根据图的性质,进行功能抽取,设计Graph接口,具体包括静态常量最大权重值99999,vertexCount()计算顶点数函数,get()获取顶点元素函数,getWeight()获取边的权值函数,insertVertex()插入顶点元素函数,insertEdge()插入边函数,removeVertex()移除顶点函数,removeEdge()移除边函数,getNextNeighbor()获取邻接点函数,DFSTraverse()深度遍历函数,BFSTraverse()广度遍历函数。
定义边类实现Comparable接口,编写构造方法,初始化起始顶点号,结束顶点号和权值;复写toString()函数,用于打印输出边的参数;实现compareTo()函数,进行起始顶点值的比较。
编写抽象图类实现Graph接口,复写DFSTraverse()深度遍历函数,BFSTraverse()广度遍历函数,增加minSpanTree_prim()生成最小生成树函数,Dijkstra算法求带权图中顶点vi的单源最短路径函数shortestPath(),Floyd算法求带权图每对顶点间的最短路径函数shortestPath()。
最后,编写邻接矩阵图类继承抽象图类,编写构造函数,初始化图的数据,分别复写抽象图类中的功能。
4、树的编写
首先根据树的性质,进行功能的抽取,设计BinTree接口,具体包括isEmpty()判断数是否为空函数,count()计算二叉树节点数函数,height()计算二叉树高度函数,preOrder()先序遍历函数,inOrder()中序遍历函数,postOrder()后序遍历函数,levelOrder()层序遍历函数,search()查找函数,getParent()获取父母节点函数,insertRoot()插入根节点函数,insertChild()插入子节点函数,removeChild()删除子节点函数,removeAll()删除全部元素函数。
编写节点类,设计三种构造方法,分别为传入空参数,传入节点数据域的数值,传入节点数据域的数值和左右子树。
编写二叉树类实现BinTree接口,实现BinTree接口中的方法,增加以下方法:create()创建新节点函数,getParent()在从某一节点开始的二叉树中获取父母节点函数,preOrder()从某一节起先序遍历函数,inOrder()从某一节点起中序遍历函数,postOrder()从某一节点起后序遍历函数,levelOrder()从某一节点起层序遍历函数,serach()从某一节点起插入节点函数,count()从某一节点起计算二叉树节点数函数,height()从某一节点起计算二叉树高度函数。
编写二叉排序类继承二叉树类,增加insert()插入元素方法,remove()删除元素方法,remove()删除节点方法。
5、哈希表的编写
编写哈希表类。包括两种构造方法,空参数法和传入表容量值法,以及hash()求元素散列地址函数,insert()插入方法,remove()移除方法,search()查找方法,toString()输出散列表信息函数。
6、API的编写
在每一个类前加一个文档注释,声明该类的用途,包含的方法,以及作者和版本信息。注意,帮助文档的编写要随着代码的编写而进行,这样会减少不必要的麻烦。当写完所有的帮助文档后,通过flie->export->选择java文件夹下的javadoc->选择要生成帮助文档的工程,选择生成地址->点击finish即可。
7、TDD的编写
由于要测试的类中的方法具有关联性,所以我通过设计不同的情景,同时对多个函数进行测试,而不是依次测试各个函数。其次,要测试的类中用到了泛型方法,所以分别设计了Integer类型的测试和String类型的测试。最终使用TestSuite功能,将所有类对应的测试类,整合到一个Test测试类中,对测试类进行统一管理和测试。
8、GUI界面的编写
通过自学图形用户界面部分,将各种数据结构类的各种方法通过图形用户界面实现出来。将各种功能的实现通过按钮来实现,其中比较重要的是,界面的设计。我的设计是,通过一个文本栏输出要操作的数据,将不同的方法对应上相应的按钮,通过操作按钮实现相应的功能。设置一个文本框,将操作的结果输出。由于时间有限,所以设计的比较粗糙。
实验结果与测试
1、完成DataStructure工程下,BinSortTreeStructure包、HashTableStructure包、linkedstructure包、MapStructure包、queuestructures包、Sort包以及stackstructures包的编写,分别包含二叉排序数类、散列表类、线性表类、图类、队列类、排序类以及堆栈类,注意关于查找的方法,没有统一封装起来,而是分别分装在美中数据结构的具体类包里,因为查找方法作为一种基本操作,已经包括在基础类中,不必在进行封装。
2、完成整个工程的TDD测试。
(1)TDD测试结果是比较全面的,具体到每一个类中的每一个方法。注意并不包含私有方法,因为我编写的程序中,私有方法是为了公有方法服务的,在公有方法的实现过程中调用了私有方法,如果TDD测试可以通过,也就间接说明了相应的私有方法的正确性。
(2)此外,在编写TDD测试的过程中,我设计每一种数据结构的情景,并不是类中的方法分离开测试的,而是一个方法的测试接着另一个方法,因为方法与方法之间是有联系的。(3)值得特别一提的是,在编写产品代码的时候,我使用了泛型这一新的结构,并在测试的过程中,分别针对整形Integer对象和字符串型String对象使用了泛型,都测试出了结果。
3、将各种数据结构类用GUI界面实现。通过自学图形用户界面的相关知识,在编程之前,首先要设计出所需的界面,实现一个框架中,包括各种功能函数的按钮,输入数据的文本框以及显示结果的文本框。
4、API的编写。由于学习java视频,我养成了边写代码边写注释的习惯,在代码写完后,相应的注释也写好了,所以直接在文件选项卡下,选择导出就可以了。
5、最终将所有代码和API文档打包成jar包,以备队友使用。
实验总结
1、TDD的编写一定要随着代码一起进行。在本次实验中,我是完成了全部的代码编写工作后,才开始写TDD的,在测试过程中,常常因为一个问题一直不成功,浪费很多时间回头找原因,而且加上编完代码也过去了一段时间,很多代码部分也有些遗忘,又不得不从头开始改起,耽误了大量的时间,记得有一个创建二叉排序数的函数的编写中,由于一个地方把大于当做小于,导致程序一直有问题,在我读了很多遍代码后,才最终发现问题。边写程序边测试,这一点是我在这次实验中最大的收获。
2、在设计类的时候,一定要学会提取和抽象,能总结成接口和抽象函数的功能,就要总结,刚开始的时候,我编写线性表时,当时只顾闭门造车,一个劲的生遍,导致链表和顺序表类的很多功能都有相似之处,但都没有抽取出来,导致一个类中有过多的冗杂的函数,阅读起来不方便,查找也不方便,通过阅读参考书,我在学习他人的代码过程中,学习了如何提取功能,建立接口和抽象类,以及父类。
3、特别的一点是,在对Sort排序类进行TDD测试的时候,由于忽略了字符串这一类型的特点,排序java10、java06、java006时,由于我的主观臆断,认为结果应该为java06、java006、java10,导致测试成功,后来发现字符串类型数据和整形数据的区别后,修改了预期结果,才使测试得以通过。不过,大多数情况下,测试不通过还是由于程序的原因,比如在创建二叉排序数的过程中,对建好的二叉排序树进行中序排序,输出的结果总是有一部分错误,有时又能正常通过,后来发现在一个if判断语句中,大于小于写反了。通过TDD测试确实能发现问题,使程序更准确、完整。
4、API的编写在编程的过程中也显得尤为重要。只有边编程边写注释,才能减少日后的麻烦,许多程序隔了一段时间后再看,会发现读不懂了,这时就体现了注释的重要意义。此外,养成良好的编程习惯,我们就会逐步成长为一名合格的编程人员。API的编写,不但是对编程者的提示,更要有提示用户的左右,所以写注释的时候,一定要注明函数的功能,参数的意义和返回值的意义。更要注意文档注释的编写,文档注释是对整个类的解释,所以要说明该类的用途和功能,以及作者和版本信息。
5、通过去图书馆借阅相关的书籍,我通过只看一部分的内容,如关于链表部分的,通过比较,最终筛选出最适合书,并以该书作为参考,实现了日后的编程。这使我查阅资料的能力得到了提高。在本次实验中,我认为我最大的收获是学会了如何自学和如何查资料,通过借阅不同的相关书籍进行比较,可以很清晰的发现各种书的差异,也可以找到最合适自己水平的书来阅读学习。
6、在本次实验中除了项目代码的完成,我也学会一些东西。比如,开发一个项目TDD测试一定要紧跟着代码的编写完成,只有这样才能保证你的代码可以使用各种不同的情况,以及在编写的过程中,及时的跟进注释的编写。如何查资料。如何快速学习。在本次的实验中,我发现有目的的学习,比盲目的学习课本要有效率的多,而且还可以保证你真正的学到了知识,这一点适合任何学科、任何事物的学习。