文档库 最新最全的文档下载
当前位置:文档库 › 基于 C++数据结构算法演示系统

基于 C++数据结构算法演示系统

基于C++数据结构算法演示系统

毕业论文

摘要

数据结构算法演示系统

数据结构在计算机科学中是一门综合性的专业基础课,它不仅设计到计算机硬件(特别是编码理论、存储装置和存取方法等)的研究范围,而且和计算机软件的研究有着更密切的关系,无论是编译程序还是操作系统,都涉及到数据元素在存储器中的分配问题。在研究信息检索时也必须考虑如何组织数据,以便查找和存取数据元素更方便。因此,它是介于数学、计算机硬件和计算机软件三者之间的一门核心课程。在计算机科学中,数据结构不仅是一般程序设计的基础,而且是设计和实现编译程序、操作系统、数据库系统及其他系统程序和大型应用程序的重要基础。

本文充分利用C++ BUILDER的RAD优点,设计并建立了一套数据结构算法的演示系统。讲解了线性表、堆栈和队列、树、图等数据结构的概念,该系统具有操作便捷、形象生动等特点,对于深化对数据结构算法的理解,提高计算机程序设计水平具有很好的促进作用,而且具有一定的实用价值,能有效地改善数据结构算法教学的质量和效率,对于其他类似系统也有很大的借鉴意义。

关键字:数据结构;算法;C++ BUILDER

Abstract

Data structure algorithms demonstration system Data structures,is a comprehensive professional foundation courses in computer science, not only to studied computer hardware design (especially coding theory, storage devices and visit methods), and researched computer software in closer relationship, whether translation or operating system, data elements are involved in the allocation of memory. In information retrieval research, data must also consider how to organize in order to identify the data elements and visit more convenient. Therefore, it is a door core curriculum between mathematics, computer hardware and computer software. In computer science, data structure is not only the basis for general programming, but also the design and realization of heavy editing procedures, operating systems, database systems and other systems procedures and the essential foundation for large-scale applications.

The full use of the RAD advantage C++ builder design and build a data structure algorithms demonstration system. On the linear tables, Duizhan and Britain, trees, maps, and other data structure concept, the system has operated convenient, vivid image characteristics of the data structure to deepen the understanding of algorithms to improve the level of computer programming in good catalyst, but with some practical value to effectively improve data structure algorithms teaching quality and efficiency For other similar systems.

Key words:Data structure;Algorithms;C++ builder

1 绪论 (1)

2 需求分析 (2)

2.1 解决问题 (2)

2.2 具备功能 (2)

3 系统设计 (3)

3.1 开发及使用环境 (3)

3.2 系统结构 (10)

3.3 详细设计 (12)

4 系统操作 (28)

4.1 主菜单操作 (28)

4.2 线性表操作 (28)

4.3 树操作 (29)

4.4 算法说明操作 (29)

结束语 (30)

谢辞 (31)

参考文献 (32)

附录 (33)

附录A 外文翻译-原文部分 (33)

附录B 外文翻译-译文部分 (39)

附录C 源代码 (45)

数据结构是在整个计算机科学与技术领域上广泛被使用的术语。它用来反映一个数据的内部构成,即一个数据由那些成分数据构成,以什么方式构成,呈什么结构。数据结构有逻辑上的数据结构和物理上的数据结构之分。逻辑上的数据结构反映成分数据之间的逻辑关系,而物理上的数据结构反映成分数据在计算机内部的存储安排。数据结构是数据存在的形式。数据结构是信息的一种组织方式,其目的是为了提高算法的效率,它通常与一组算法的集合相对应,通过这组算法集合可以对数据结构中的数据进行某种操作。数据结构课程的主要目的是介绍一些常用的数据结构,阐明数据结构内在的逻辑关系,讨论它们在计算机中的存储表示,并结合各种数据结构,讨论对它们实行的各种运算的实现算法。很多算法实际上是对某种数据结构施行的一种变换,研究算法也就是研究在实施变换过程中数据结构的动态性质。

数据结构,作为计算机学科的基础性专业课程,其在计算机科学中的及其重要,课程学习的好坏,直接关系到学员后期计算机水平的高低。而这门课程一直因为过于抽象,难以理解,而让人望而止步。如果能够把这门抽象的课程变得具体而生动,必将提高学习人员兴趣,增加其积极性和主动性,也有利于人员的对此课程的学习。

基于这些目的,我们开发了这个数据结构算法演示系统,数据结构是我们所做的系统的主要理论基础,我们完成了线性表、堆栈、队列、树、图几个主要结构,在学习数据结构这门课程的时候,我们了解了这些结构的算法,当时也做过一些相关的程序,在此基础之上,我运用c++ builder开发工具,把这些算法演示出来。

数据结构算法演示系统可以演示线性表、堆栈、队列、树、图等几个基础结构的算法,辅助一些算法说明,让使用者更好地掌握算法,在帮助中把演示的具体过程和操作做详细的介绍。

该系统具有操作简单、形象生动,能很好地改善人员对数据结构课程的学习理解,从很大程度上提高人员的学习质量和效率。

2 需求分析

2.1 解决问题

做为一个数据结构演示系统,首先我们确定要演示的内容,在本系统中,我们对线性表、堆栈和队列、树、图几个主要数据结构做了讲解;接着,对四种算法的说明也是必不可少的,这样配合演示,可以达到更好地效果;最后,作为我们设计的演示过程,使用者对操作不是太了解,我们有必要做个详细的操作过程,让使用者更好地操作系统。

2.2 具备功能

系统由数据结构、操作、帮助、程序四个部分组成。现分述如下:

数据结构由线性表、堆栈和队列、树、图等四个部分组成,分别对应数据结构的四个部分。线性表又分为链表概念、链表模型、链表操作、双向链表四个部分,堆栈和队列分为基本堆栈、基本队列、循环队列三个部分,树分为数据二叉树、结构二叉树、类二叉树,图分为图表示、图搜索、最短路径。

操作由线性表说明、堆栈说明、队列说明、树说明、图说明组成,对各数据结构的算法说明。

帮助由关于和帮助组成,是本系统的一些说明和对演示过程的操作详细说明。

程序部分由退出组成,完成系统的终止。

3 系统设计

3.1 开发及使用环境

C++ BUILDER

3.1.1 C++ BUILDER介绍

提起Borland C/C++,相信业界的许多朋友都会感慨万千,因为它曾带领很多人跨进了Windows开发的大门。和美国Inprise公司(原Borland公司)其他面向企业分布式系统的开发工具(如Delphi 、Jbuilder )相比,新近推出的最新版本C++ RAD(快速应用开发)工具――Borland C++ Builder 4,无论是在开发环境、分布式应用系统开发、支持已有C++资源方面,还是在快速开发Web及Internet应用程序、数据库处理等方面,都表现出了其独特的一面。

(1)全新的集成开发环境

C++ Builder保留了使用Framework(如:OWL、MFC)的开发方式,融合了Visual Basic、Delphi等开发工具的面向组件的开发方式。C++ Builder的集成开发环境提供了120多个VCL组件,使开发人员不需太多编码,就能够实现很多复杂的功能,体现了软件的“重用性”原则。C++ Builder的用户界面也非常友好,易于使用,并且采用了停驻式(docking)工具条,可以自由组合集成开发环境窗口和工具条的排放方式。在编码过程中,还可以使用CodeExplorer技术对源代码进行管理。CodeCompletion技术使编译器能够自动列出VCL 组件的可用属性和方法供程序员选择,而不必手工输入冗长的代码。C++ Builder的集成开发环境如图1所示。

(2)简化了分布式应用系统的开发

企业向多层分布式系统跨越已经成为了一种必然趋势,目前分布式运算标准主要有Microsoft 的DCOM和OMG的CORBA,是否支持这两种标准决定了开发工具的适用领域和范围。C++ Builder可以说是目前唯一同时支持CORBA和COM的C++集成开发环境,因此既适用于基于ORB的分布式开发,又适用于基于COM的Windows开发。C++ Builder 内置了VisiBroker3。3,它是目前全球分发数量最多的CORBA ORB,并且包含了Event Service和NamingService等标准CORBA服务,从而为开发CORBA应用提供了可能。C++ Builder 将CORBA IDL 编译器集成在其开发环境中,通过配合各种向导(Wizard),可以快速生成CORBA Client和Server的源程序代码框架,这对于开发CORBA产品的朋友来说,确实是非常方便的。图2显示了C++ Builder中建立CORBA对象的各种向导。

在Microsoft COM方面,C++ Builder 同样提供了各种向导,可以一步生成COM标准组件、OLE Automation组件及ActiveX组件,您可以在Windows环境下大显身手。C++ Builder 提供的MIDAS2同时支持CORBAIIOP、DCOM、DCE RPC以及TCP/IP等多种连接方式,适用于分布式系统的开发。比如,非Windows环境上的Java应用程序,可以通过CORBA IIOP使用C++ Builder开发出来的应用程序服务器。从而使用户可以在原有系统基础之上构建跨平台、跨程序语言的分布式应用系统。

(3)对已有C++资源的支持

用户可能会关心,对于过去开发的基于Borland C++ OWL和Microsoft MFC的程序,C++ Builder是否能够兼容?回答是肯定的。C++ Builder的另一特性就是提供了MFC4。2版的函数库,强化了对Microsoft Visual C++源代码的兼容性,可以直接编译MSDN与各种SDK中的范例程序。通过MFC向导,还可以生成MFC的代码框架。

除此之外,C++ Builder能够编译原有的BorlandC++ OWL程序码,因此就不必担心以前的工作白做了!C++ Builder中提供了符合ANSI/ISO标准的C++编辑器,还能够开发可移植于非Windows平台的C++程序。

(4)快速开发Web及Internet应用程序

目前,基于Internet的开发已经成为一种时尚。C++ Builder在开发Web及Internet应用方面的功能也非常强大。C++ Builder提供了21个Internet通信协议组件,用于Internet 应用程序的开发。开发人员可以建立“零配置”、基于Web浏览器的“瘦客户”应用程序。C++ Builder同时支持CGI、WIN-CGI、ISAPI及NSAPI等标准,使开发人员利用现有的开发技术就可以用可视化的方式开发跨平台的Web应用程序。运用ActiveForm/ATL及WebDeploy技术,还可以实现ActiveX组件的Web分发。

(5)强大的数据库处理功能

C++ Builder提供了对Oracle8、Microsoft SQLServer 7、Informix 9、Sybase、IBM DB 2 UniversalServer、InterBase 5。5等大型数据库的高速驱动程序,并支持Oracle8的对象关联延伸功能(如图3所示),如Abstract Data Type、Nested Tables、Variable LengthArrays、Object Pointers(REFs)及External FileReference等。同时C++ Builder还保留了对MicrosoftAccess 97、FoxPro、Visual dBASE及Paradox等本地数据库的处理能力。因此,无论是大型的数据库应用系统开发,还是小型的数据库管理系统,C++ Builder都有其用武之地。

C++ Builder还提供了MTS 组件向导,用于快速生成支持Microsoft Transaction Server 的COM组件。BDEResource Dispenser使用户可以在MTS中使用BDE存取数据库,保证了MTS对数据库的两阶段提交(Two PhaseCommit)及资源管理的能力。

(6)强大的调试功能

C++ Builder强化了原有的Module View、EventLog View及Inspect Local Variable等调试窗口的功能,并在Windows NT环境中提供多线程调试的新功能,使用户可以在某一特定过程中跟踪程序代码。C++ Builder针对多层分布式开发环境提供了远程调试能力,开发人员可以通过网络直接对远端的应用程序服务器进行调试,从而简化了多层应用系统的开发和维护工作。

(7)其他特点

C++ Builder还有很多新增的功能,如:针对Windows 98提供了PageScroller、MonthCalendar等Windows 98格式的新组件,并支持Windows98的多重屏幕显示功能及Microsoft Office97格式的选择选单和停驻式(docking)工具条。对界面的处理上,可以控制

窗口的最大/最小尺寸以及窗口尺寸变动时其中组件的相对位置和比例,等等。

总之,C++ Builder 的强大功能并不是通过笔者有限的介绍所能够涵盖的,在C++海洋里遨游的朋友不妨亲自尝试一下C++ Builder,体验一下它的灵活与强大,相信您定会“恋恋不舍”的。

3.1.2 C++ BUILDER与Visual C++对比

首先,从它们的应用程序框架(Application Frame,有时也称为对象框架)进行比较。Visual C++采用的框架是MFC。MFC不仅仅是人们通常理解的一个类库。(同样,Del phi 和C++Builder使用的VCL的概念也不仅仅是一个控件库。)你如果选择了MFC,也就选择了一种程序结构,一种编程风格。MFC早在Windows 3.x的时代就出现了,那时的Visual C++还是16位的。经过这些年的不断补充和完善,MFC已经十分成熟。但由于原型出现得比较早,MFC相比于VCL落后了一个时代。尽管微软对MFC的更新没有停止,我也经常读到持"只要Windows不过时,MFC就不会过时"之类观点的文章,但就象Inprise(原Borland)的OWL框架的淡出一样,MFC的淡出也是早晚的事。如果MFC青春永驻,微软的开发人员也不会"私自"开发出基于ATL的WTL呀。当然,WTL的地位不能和MFC比,它并不是微软官方支持的框架,封装的功能也相当有限。但至少也反衬出了MFC存在的不足。

我以为,最能体现一个应用程序框架的先进性的是它的委托模型,即对Windows消息的封装机制。(对Windows API的封装就不用说了吧。大同小异,也没什么技术含量。如果高兴,你也可以自己写一个类库来封装。但对Windows消息驱动机制的封装就不是那么容易的了。)最自然的封装方式是采用虚成员函数。如果要响应某个消息就重载相应的虚函数。但出乎我的意料,MFC采用的是"古老"的宏定义方法。用宏定义方法的好处是省去了虚函数VTable的系统开销。(由于Windows的消息种类很多,开销不算太小。)不过带来的缺点就是映射不太直观。好在较新版本VC带的ClassWizard可以自动生成消息映射代码,使用起来还是比较方便的。但和VCL的委托模型相比,MFC的映射方法就显得太落后了。而C++Builder对C++语言进行了扩展,以便引入组件、事件处理、属性等新特性。由于功夫做在编译器级,生成的源代码就显得十分简洁。但是由于扩展的非标准特性,使用VCL的C++Builder的源代码无法被其它编译器编译。而MFC的功夫做在源代码级,虽然消息映射代码较为复杂且不直观,但兼容性非常好。只要你有MFC库的源代码(随VC 企业版的光盘提供),你的MFC程序理论上用任何符合ANSI标准的编译器均可编译通过。C++Builder 3以上版本可以原封不动直接编译Visual C++程序,很多人认为这是C++Builder 的兼容性好,实际上很大程度应归功于MFC的兼容性好。微软辛辛苦苦用标准方法写MFC,却为对手制造了方便。不知他们作何感想?而因为C++Builder对语言作了扩展,VC不能编译C++Builder的程序。看来在这方面VC要输给C++Builder了。而且VCL所支持的组件、属性等都是MFC所缺乏的特性。虽然VC也能支持组件,但要通过AppWizard 先生成一个"包裹"类(wrapper),不如VCL来得简洁。有很多人使用C++Builder就是冲着

控件板上那一大堆组件来的,VC虽然能使用的组件也很多(也许不比C++Builder少),但由于不方便而对RAD程序员没有吸引力。

C++Builder的VCL比Visual C++的MFC先进的另一个特性是异常处理。但令人啼笑皆非的是,它的异常处理代码有bug,有时会无端抛出异常。不知道在最新的版本中有没有改正了。而VC的框架MFC也不是一无是处。经历了那么多年的发展和完善,MFC功能非常全面,而且十分稳定,bug很少。其中你可能遇到的bug更少。而且有第三方的专门工具帮助你避开这些bug。如此规模的一个类库,能做到这一点不容易。不要小看了这一点,很多专业程序员就是为这个选择VC的。而C++Builder的VCL的bug就相对较多了,而且有些它自己带的示例程序都有错误。看来Inprise还有很长的路要走。

再从它们的易用性比较。VC有ClassWizard、SourceBrowser等一系列工具,还附带Visual SourceSafe、Visual Modeler等强大的工具,易用性非常好。(VC自带建模工具Visual Modeler,也许说明了它才是工程级的开发平台,与C++Builder的定位不同。)它所带的MSDN这部"开发者的百科全书"更是让你"没有找不到的,只有想不到的"。而且它的AutoComplete之类小功能也比C++Builder要体贴。C++Builder的新版本虽然也提供了这一功能,但它的提示要等好几秒才出来,有时你不经意间把鼠标停在某一处,也要等硬盘响好几秒,这可是在566Mhz的赛扬II上呀。不要笑我琐碎,有时一个开发工具的成熟和易用,就是从这些小地方体现出来的。C++Builder作为RAD工具,理应强调易用性。但与VC相比还显出不成熟。这是不应该的。

再来看看它们的可移植性。Inprise正在开发C++Builder和Delphi的Linux版本,代号为Kylix。也许通过Kylix,用VCL构架编写的Windows程序向Linux移植成为可能。但这只是可能。因为在目前Inprise的兼容性工作做得并不好。C++Builder可以编译VC程序还要多谢微软使用标准方法写MFC,而它自己各个版本之间兼容性却不太好。低版本的C++Builder不能使用高版本的VCL组件(这还别去说它),而高版本的C++Builder竟然不能使用低版本的VCL组件。真是岂有此理,我很少看见软件有不向下兼容的。如果Windows 98不能运行95的程序,Windows 95不能运行3.x的程序,Win 3.x不能运行DOS程序,你还会用Windows吗?如果不是C++Builder的其它某些方面太出色,光是这个向下不兼容就足以让我抛弃它。而且虽说通过捆绑编译器,C++Builder可以编译Delphi的Object Pascal代码,但C++Builder仍不能使用为Delphi开发的VCL组件。所以一个组件有for D1/D 2/D3/D4/D5/C1/C3/C4/C5这些不同版本是常有的事,而且随着C++Builder版本的升级可能还会增加。希望Inprise能先解决同门兄弟的兼容性问题。而微软的VC就没有这类问题MFC1.0的程序也可以毫无障碍地在VC6.0下编译通过。

再来看看它们的前景吧。实际上,技术的进步在很多时候是此消彼长的。当初Borland 的Turbo C和Borland C++几乎是唯一的选择。微软的Quick C(现在还有人知道这个产品吗?)和Microsoft C/C++从来也没有成为过主流。但Borland C++又流行了多少年呢?不久就被新崛起的Microsoft Visual C/C++压下去了。现在的C++Builder又有后来居上的态势,如果稳定性再提高一些,bug再少一些,有希望成为主流。但Inspires的总体实力不及微软,

这也是无可争议的。从C++Builder 5的Release Notes中的Known Issues部分,以及它们的帮助文档的规模和质量都可以看出。(哪个同类产品的帮助文档能和MSDN比呢?)Inprise 公司应从Netscape吸取教训,不要让C++Builder成为第二个Netscape Communicator。(Communicator也是一度技术领先,甚至曾占据了大部分的浏览器市场,但似乎后劲不足,而且6.0 PR1、2中bug多多,现在被IE压得抬不起头。)C++Builder是Inspires的旗舰产品之一,前景应当还是比较乐观的,而且Inspires已经在向Linux进军了,而微软还迟迟没有动作,难道非要到Linux成燎原之势(或许已经成燎原之势了)才会奋起占领这个新兴市场?似乎他们对Linux的态度与几年前对互联网的兴起的反应迟缓有些相似。但后来......唉,真希望Inprise不要步Netscape的后尘。C++Builder是一个很有前途的开发工具。遗憾的是,Inprise公司Delphi的创始人已经跳槽到微软去主持Visual J++项目了。但愿对Inprise冲击不会太大。微软的Visual C++的前景又怎样呢?Visual Studio 7.0不久就要推出了。不知能不能在保持稳定性的同时在技术的先进性上赶上C++Builder。另外,这一版本将加强网络开发的特性。看来微软虽然被判解体,开发实力可是一点没打折扣。

就技术(主要指应用框架)来说,C++Builder目前领先于Visual C++。但多多少少的不尽人意之处对Inprise"想说爱你不容易"。而VC尽管发展到今日已十分完善,但MFC框架已是明日黄花了。如果不使用MFC,目前又没有合适的替代品。WFC是支持组件、属性和事件的,但那是Visual J++里边用的;ATL也很先进,但是用来进行COM/ActiveX开发的;基于ATL的WTL也不错,可惜是非官方作品,也未必比VCL先进。微软最近提出了C#(读作C Sharp)语言方案,但那属于和Java同一类的东西。看来是金无足赤啊。根据你的需要做选择吧。实际上Visual C++和C++Builder也不是单单竞争关系。它们在许多领域并不重叠,甚至是互补的。到底怎样取舍,要根据你的项目特性决定。如果你开发系统底层的东西,需要极好的兼容性和稳定性,选Visual C++吧。你可以只调用Windows的各种API,不用MFC。如果你写传统的Windows桌面应用程序,Visual C++的MFC框架是"正统"的选择。如果你为企业开发数据库、信息管理系统等高层应用("高层"是相对于"低层/

底层"而言的,不是说技术高级或低级。)而且有比较紧的期限限制,选C++Builder比较好。如果你用的语言是Object Pascal,Delphi是唯一的选择(如果GNU Pascal等免费编译器不考虑的话)。如果你原先用Delphi(Object Pascal语言),现在想改学C++,应当先C++Builder。熟悉的界面和相同的框架会让你的转轨事半功倍。

3.1.3 BCB的调试

程序的bugs越少,最终用户对这个程序的评价越高。而开发人员事先对bugs的处理越多,最终用户能提供的关于bugs的信息就越多,也越准确,这样,开发人员在接到最终用户反映之后,就能够快速找到出现bugs的那部分代码,并以最快速度发布程序的升级包。

(1)写易读的代码

第一点,大概也是最重要的一点,就是写干净易读的代码。易读的代码是很有价值的。请想象一下,如果随便扫视一眼代码或注释,就能立刻知道这段代码的的作用,以及在写

代码的时候为什么要这样写,当时的思路是什么,那么就可以节约大量时间。这样的代码,在写的时候可能会稍稍慢一些,不过,当你调试程序时,就不会花上几个小时来寻找bugs,相反,你可以快速,简单的完成除错工作。这时,你就会觉得多花一些时间使程序易读是很值得的。

所以,在写程序的时候,应该养成自己的风格,或是读一读Scott的关于代码风格的文章。

(2)使用Exceptions和Exception的处理方法

除去一些少数的情况,开发人员不可能总是依靠于集成的调试工具。所以,学会用其它的方法来找到烦人的bugs是很重要的。一些重要的、处理的错误可能会在窗体之外发生。在C++标准制定出来之前的黑暗日子里,在程序里面发出发生错误的信号,通常是通过返回错误代码完成的(现在这种方法仍然应用于OLE技术和一些Winapi函数),这样的处理方法很容易就会被忽略。(比如说,你经常检查winapi函数的返回值吗?)所以,出现问题的可能性并不小。由于以上的原因,需要一个这样的机制,它不能忽略这些错误,而且,这个机制应该能被我们控制和自定义的。在这样的需求下,异常处理机制出现了。需要一个特殊的错误类型吗?简单,定义一个新的异常类型就行了(和定义一个类的方法差不多),然后抛出(throw)它。

C++Builder定义了try {} catch (…) {}机制。这和刚刚定义的异常机制的结构很相似。这个机制完全可以按照需要自定义。要使用异常处理了,只要把要执行的代码放到try块里面,为了让程序知道出现异常后应该做什么,还需要定义一个catch()或是__finally块。Catch()语句里面可以指定一个要捕捉的类型或是变量,甚至可以用它来捕捉树结构或是继承类的异常,如果捕捉了基类的异常,它就能捕捉到继承这个基类的所有的类的异常。比如,在VCL中,所有的异常都是继承于Exception类。所以,catch(Exception& E)可以捕捉到除了EsocketError的所有VCL异常。为了让这个机制更强大,C++Builder中还定义了catch(…)语句。(没错,就是三个点)使用这条语句可以捕捉到所有的异常。还有更多的功能吗?当然,你可以添加更多的catch()语句,可以向使用if…else if…语句那样使用它。注意,在一系列的catch()语句中,错误不会被重复的捕捉,也就是说,如果前面的catch()语句捕捉到了错误,后面的catch()语句将不会捕捉这条错误。

这个机制还有更多的功能。如果你想处理异常,但是不想在处理的位置停止,那么可以重新抛出异常。这时,程序将继续寻找下一个catch()语句来处理这个异常。这个方法和“throw”差不多。这样,你处理过的异常会再次被抛出,继续寻找下一个catch语句来处理它。

最后一个要说的是__finally(这不是标准的用法,是Borland添加的一个好方法),在__finally{}程序块中代码,无论是否发生异常都会被执行。这是一个清理程序中使用new 分配的本地变量,设置用作旗标的变量值为正常的好位置。(比如,把一个等待状态的光标图标设置为正常光标。)

就是这些了。有时间的话,请看看C++Builder帮助文件中的Exception类以及继承

Exception的类。这些将对于理解本节所说的内容有很大帮助。

(3)使用记录机制

不可能总是用调试器来调试代码,在某些情况下,可能无法使用内部集成的调试器,这时候,就不得不依靠其他手段调试程序了。(比如:Windows NT服务程序,ISAPI/CGI程序,实时应用程序等等)。这时候,有经验的程序员可能会借助古老的调试方法,例如,使用一些分类的记录机制来确定程序实际运行的过程。现在有一系列的方法可以简单的完成这样的工作。下面将介绍3种方法。

第一个方法:OutputDebugString。(WinAPI: VOID OutputDebugString(LPCTSTR lpOutputString);)很幸运,微软彻底的实现了调试子系统。它包括的一些特点可能让你想把自己的记录系统扔掉。应用程序在调试器进程中运行时OutputDebugString将用C字符串把调试器输出的信息打印出来。如果程序没有在调试器进程中运行,它将忽略这些调用。它会很好的在客户的机器上运行,不会弹出信息窗口。如果在发布给客户的时候,忘记去掉这些代码程序仅仅会变慢一点,不会有别的不良后果。

第二个方法:使用了Gexperts,通过dbugint.pas接口进行调试。它是个可以称之为伟大的程序,你可以把它分发给客户。和OutputDebugString一样,如果客户没有这个程序,它就根本什么也不作。(它会自动检测机器上是否安装了客户端)。要使用dbugintf,它很容易被加入到你的工程中,加入#include "dbugintf.HPp"(要把它加入工程,然后会编译它的pascal文件)。然后,你就可以直接使用SendDebug(要送到记录文件的字符串); 或者,你需要它更机警一些,可以使用SendDebugEx(它给TMsgDlgType增加了一个新的消息类型)SendMethodEnter, SendMethodExit, SendSeparator等等(用法都差不多)。如果你打算给最终用户分发客户端(Gdebug.exe),不要忘记include所需要的程序包。Gexperts可以在https://www.wendangku.net/doc/ba204918.html, 得到,它是免费的。

第三个方法:大概是最艰苦的方法,就是使用自己的记录控制。这个方法可能不是想象的这么简单。可能首先会想到“在窗体上扔一个RichEdit,把它设置为只读的,然后往里面写记录”是这样吧?理论上不错,但是,实施起来…首先,使用RichEdit控件来做记录,会大大降低应用程序的速度,还会在内存中造成碎片,甚至丢失内存。通常,在运行10分钟左右之后,会使整个计算机的速度变慢!所以,如果希望在自己的记录中能够使用彩色和图标,那么最好自己创建一个组件。如果没有这么高的要求,那么有一个简单有效的方法,就是使用ListBox控件作记录,把ListBox的Style属性设置为lbOwnerDrawFixed,这样句柄将会自绘。(Gexperts的控制台就是用这样的方法制作的)。

(4)将记录和异常处理结合使用

不用总是担心可能会发生什么偶然的异常。一般来说,通过很多的bugs测试后(尽量折磨程序,看看它会不会崩溃),应用程序在运行是应该不会出现什么错误。下面的这个技术,建议组件开发者,在第一次把组件放在IDE环境测试的时候,很应该遵守。一个在IDE中产生的异常会导致很多问题,甚至可能无法重新启动IDE也不能恢复。这个技术很简单。在代码中每一个函数或是主要的函数中加入:

try

{

//函数的代码

}

catch(Exception &E)

{

SendDebugMessage(“Exception caught in classname::functionname of type:”+E.ClassName() +”with the message:”+E.Message);

};

把字符串中classname 和functionname 替换成相应的类名和函数名。在出现错误时,你会立刻知道错误发生的位置。这样也就不至于强制重起IDE的了。

ClassName()给了什么样的帮助呢?它只是用于返回字符串“Exception”吗?每一次,E都被声明为异常类型?这是VCL另一个优秀的地方,所有的类都从Tobject继承,所以,这些类都能自动获得正确的类型和基类的类型,所有的更多的信息都可以在这里找到。(请参见Tobject的帮助)所以,尽管使用了Exception &E,其中的E.ClassName()将返回捕获到的产生异常的实际类名。得到这些好处需要付出的代价是编译出来的可执行文件变大了一些。所有的Delphi/Cbuilder用户都注意到了这一点,但是说没有付出就没有收获。在https://www.wendangku.net/doc/ba204918.html,/的howto栏目可以看到Xiphias的一系列文章。其中,他提到了使用TStringList作记录的方法:先将错误通过TStringList的Add方法加入到StringList里面,然后使用SaveToFile保存到硬盘上。不过要注意在程序结束的时候不要忘记使用SaveToFile()方法把TStringList保存起来。或者,也可以每次捕捉到异常之后都保存一次。

3.2 系统结构

主菜单模块由数据结构、操作、帮助、程序四个部分组成。

数据结构模板由线性表、堆栈和队列、树、图等四个部分组成。线性表又分为链表概念、链表模型、链表操作、双向链表四个部分,堆栈和队列分为基本堆栈、基本队列、循环队列三个部分,树分为数据二叉树、结构二叉树、类二叉树,图分为图表示、图搜索、最短路径。

操作模板由线性表说明、堆栈说明、队列说明、树说明、图说明组成。

帮助模板由关于和帮助组成。

程序模块由退出组成。

系统的功能模块如图3-1所示。

本系统是由我与另外一个同学合作完成的,根据系统的结构,我们对各自的任务做了明确的分工。

我在本系统中所做的工作是:

1、详细分析了系统需求,提出了系统设计方案,并进行了论证;

2、分析了RAD设计方法的利弊,并选定了设计方案。

3、主菜单、线性表、树、操作四部分模块的设计。

3.3 详细设计

3.3.1 主菜单

(1)主菜单主要由一个菜单控件、一个显示文本、三个按纽、二个可供长文本输入/出等七个控件组成。如图3-2所示:

(2)设计思想:

作为一个演示系统的菜单,应给人一个直观的感觉,有个醒目的标题,通过一个菜单控件,连接我们设计的各种数据结构的算法演示;两个文本输入,用于对算法的说明,辅助使用者对算法的学习;作为一个系统,一个帮助模块是不可缺少的。主菜单的流程图如图

(3)控件介绍:

C++ Builder的组件工具箱(Component Palette)提供各种制作组件的工具,包括文字标签、文本框、图象组件等。

在本系统中,用到了MainMenu(建立主菜单)、PopupMemu(建立弹出式菜单元件)、Label(在窗体上显示文本信息的工具)、Edit(建立文本框的工具)、Memo(可以让用户输入文字信息,功能较文字标签更多元化)、Button(在窗体上建立命令按纽组件,在窗体上单击此按纽时,可以执行对应的程序代码)、ListBox(在窗体建立列表框组件,提供数据选项)、ComboBox(它可建立下拉式列表,是列表框与文本框的组合)、ScrollBar(用来建立滚动条组件)、GroupBox(在窗体上建立框架组件)、RadioGroup(建立选择群组组件)、Panel(存放其他组件的容器组件)、ActionList(存放执行动作的组件);Bitbin(可有图标的按纽)、StingGrid(字符串)、Image(显示图象图片)、Shape(基本图形的建立)、Bevel(建立边框面板)、TabControl(建立标签集)、ImageList(图象序列)、RichEdit(多功能编辑)、StatusBar(状态显示)、Timer(时间时间控制)这些组件。

3.3.2 线性表模块

(1)在菜单中,我们通过调用WinExec函数,以执行外部命令的方式,调用链表概念.exe 程序,来完成链表概念的演示。源代码如下:

NewFileName=ExtractFilePath(Application->ExeName)+"链表概念.exe";

i=WinExec(NewFileName.c_str(),SW_SHOWNORMAL);

在链表概念的实现中,比较数组与链表的区别,两者最明显的差别在于存储空间的配置上,数组是固定配置存储空间,因此存取上受到限制,如果超过范围则会产生无法预期的状况。

此程序是用一组地址连续的存储单位依次存储线性表的数据元素,以此实现线性表的顺序存储结构,这种存储结构的线性表叫顺序表。如图3-4所示。

(2)在菜单中,我们通过调用WinExec函数,以执行外部命令的方式,调用链表模型.exe 程序,来完成链表模型的演示。源代码如下:

NewFileName=ExtractFilePath(Application->ExeName)+"链表模型.exe";

i=WinExec(NewFileName.c_str(),SW_SHOWNORMAL);

在链表模型的实现中,此程序是一个用c++类方式编写的链表模型。线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)。因此,为了表示每个数据元素与其直接后继数据元素之间的逻辑关系,对数据元素来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息。

根据以上思想,我设计该程序的运行页面如图3-6所示。

(3)在菜单中,我们通过调用WinExec 函数,以执行外部命令的方式,调用链表操作.exe 程序,来完成链表操作的演示。源代码如下:

NewFileName=ExtractFilePath(Application->ExeName)+"链表操作.exe";

i=WinExec(NewFileName.c_str(),SW_SHOWNORMAL);

在链表操作的实现中,此程序是链表的基本操作模型,在这种存储结构中,容易实现线性表的某些操作, 在此程序中,我们重点实现了链表的插入和删除。

假设我们要在线性表的两个数据元素a 和b 之间插入一个数据元素x ,已知p 为其链表存储结构中指向接点a 的指针,如图3-8(a)所示:

为插入数据元素x ,首先要生成一个数据域为x 的结点,然后插入在单链表中。根

据插入操作的逻辑定义,还需要修改结点a 中的指针域,令其指向结点x ,而结点x 中的指针域应指向结点b ,从而实现3个元素a 、b 和x 之间逻辑关系的变化。插入后的单链表如图(b)所示。假设s 为指向结点x 的指针,则上述指针修改用语句描述即为:

s->next=p->next ; p->next=s;

反之,如图3-9所示在线性表中删除元素b 时,为在单链表中实现元素a 、b 和c 之

间的逻辑关系的变化,仅需要修改结点a 中的指针域即可。假设p 为指向结点a 的指针,则上述指针修改用语句描述即为:

p->next=p->next->next;

可见,在已知链表中元素插入或删除的确切位置的情况下,在单链表中插入或删除

一个结点时,仅需修改指针而不需要移动元素。

相关文档
相关文档 最新文档