本书是为计算机科学专业二级课程编写的,在美国许多大学称之为CS 2课程。本书将授课重点放在规范说明、设计、实现以及基本数据类型的使用上,其中有关使用的内容通常在第二学期的课程中讲授。此外,本书涵盖了重要的编程技术,并提供各自独立的抽象技术、面向对象编程、大O时间分析算法和排序等内容。.
我们假设学生已经完成了《计算机科学导论》和《程序设计》等课程的学习,但本书还是包含了一些基础课程中没有完全涵盖到的主题(例如递归和指针)。在本书中,所有的代码均采用C++语言编写,但有关C++类的内容比较浅显,因此本书仍旧适合那些以C语言而不是C++语言作为程序设计语言入门的学生。根据以往的经验,这些学生需要对C++输入与输出技术(参见附录F)有所了解,此外还需要学习有关C++参数类型(参见第2章)的内容。当C程序员克服了有关输入/输出和参数的障碍后,他们将能够领略类和其他C++面向对象的特征。需要说明的是,根据学生不同的知识背景,本书可以有多种不同的学习方案,尤其是对那些具有较强应用背景的学生来说,可以有选择地学习本书的内容。
01 第3版:新增内容和附加的Web支持
在第3版中,每种数据类型的讲授顺序和主题概要均与第1版相同。对于那些已经采用较早版本进行授课的教师来说,仍旧可以利用本书继续教学,只是需要做一些改变。这些改变是由于C++标准模板库容器类不断增长的内容而引发的,特别是:
·第1章和附录L新增有关异常处理的内容。
·第5章扩展有关常量指针的正确用法。
·第6章扩展有关标准模板库迭代器、集合、多集的内容。
·第9章新增递归示例。
·第12章新增一个利用vectors容器实现散列表的项目。此外,通过利用标准模板库容器作为基本数据结构可以成功地实现其他项目,例如B树。
·第12章和附录H扩展有关列表、映射、多重映射类的内容。
在本书的课程中,仍旧着重要求学生必须理解所有层次的数据结构,包括:规范说明、设计、实现、测试和分析。然而,从长远来看,将要在计算机科学领域继续深造的学生将会对标准模板库(Standard Template Library,STL,已经规范为1998标准的一部分)的数据类型有更进一步的应用,例如利用STL类来成功实现诸如B树等复杂的数据结构。
从本书中,读者也会发现以下内容:
·许多新的自测习题
·新的编程项目
访问我们的项目网站www.cs.colorado.edu/~main/dsoc.html可以获取我们新开发的项目。
02 每种数据类型的5个步骤
总体来说,第3版保留了最经典的数据类型:集合、包(或多集)、序列、有序列表(利用“小于”操作符排序)、堆栈、队列、表和图。此外,还额外补充了一些数据类型,例如优先队列。上述每种数据类型都将会按照下列固定的模式进行介绍。
第1步:抽象地理解数据类型。在这一层次,学生可从概念和图形的层次上获取有关数据类型及其操作的理解。例如,学生可以采用可视化的方法理解堆栈及其元素的入栈和出栈操作。学生可以理解简单的应用程序,并手动加以实现,例如利用堆栈翻转一个单词的字母次序。
第2步:将数据类型的规范说明编写为C++类。在这一步中,学生将学会如何为实现数据类型的C++类编写规范说明。规范说明包含构造函数、公有成员函数的原型和其他公有属性(例如一个用于决定堆栈最大尺寸的基本常量)。每个成员函数的原型随同用于完整描述函数行为的前置条件/后置条件一起发布。在这一层次中,规范说明与任何选定的特定实现技术是无关的,让学生意识到这一点非常重要。事实上,可以为同一数据类型的几种不同实现使用相同的规范说明。
第3步:使用数据类型。在理解规范说明之后,学生可以编写一些小的应用程序或者演示程序来展示数据类型的使用。这些应用程序只是基于数据类型的规范说明,因为我们还没有完成数据类型的实现。
. 第4步:选择适当的数据结构,继续设计和实现数据类型。在对数据类型有了很好的抽象理解之后,我们就可以选择适当的数据结构了,例如定长数组、动态数组、节点的链表或节点构成的二叉树。对于许多数据类型,我们最初的设计和实现将会选择较简单的方法,例如采用定长数组。随后,我们会使用更加复杂的基本结构来重新设计和实现相同的数据类型。
由于使用的是C++类,数据类型的实现将选定的数据结构(数组、指针等)作为类的私有成员变量。对于每个已经实现的类,本书强调需要清楚地理解将私有成员变量和数据类型的抽象概念相关联的规则。我们要求每个学生能用简洁的英文句子写出这些规则,并且称这些规则为抽象数据类型的不变式。一旦不变式编写完毕,学生就可以继续实现各种成员函数。不变式有助于编写正确的函数,这是因为:(a)当函数开始执行时,每个函数(除了构造函数)均知道不变式为真;(b)当函数结束时,每个函数(除了析构函数)都负责确保不变式再次为真。
第5步:分析实现。每个实现的分析包括:正确性、灵活性(例如采用固定尺寸还是动态尺寸)和操作的时间分析(利用大O表示法)。当利用多种方法实现相同的数据类型之后,学生就会有牢固的基础来进行这些分析。
03 在课程结束时,学生将会学到什么
在本课程结束时,学生将能够彻底地理解数据类型。他们将学会如何使用数据类型;如何通过多种方式实现这些数据类型;明确不同实现的实际效果。学生能够利用大O分析探究效率,通过参考类的不变式验证实现的正确性。
本课程的重要持久影响之一是对规范说明、设计和实现方面的体验,以及程序推理能力的提高。但最重要的也许是展示了能够简单地应用于多种情况的类。学生无需每次都从头开始编写所有的一切。我们告诉学生,将来某一天,当他们正在思考某个问题的时候,可能会突然发现大量的工作原本可以用包、堆栈、队列等方法来完成,并且这些工作根本不需要真正动手去实现,而是可以不加修改地直接利用本学期编写的包、堆栈、队列等来完成。或者,更有可能的是,他们将可以利用标准数据类型库中各种熟悉的数据类型,例如C++标准模板库。实际上,本书介绍的数据类型只是标准模板库的精简版本,因此当学生开始进一步学习真正的STL时,他们将会有一个较为熟悉的基础。在此基础上加以实现时,学生将会知道哪种数据类型正是他或她所需要的,此时学生将会成为一名真正的程序员。
04 其他基础知识..
贯穿本课程,除了讲授基本的数据结构之外,还将为“真实程序设计”的其他方面打下基础,并涵盖以下基础知识:
面向对象编程 通过让学生深入理解C++类来为面向对象编程(Object-Oriented Programming,OOP)打下基础。在课程的早期将会介绍有关类的重要内容:成员函数的概念、私有和公有成员的区别、构造函数的用途和操作符重载等。这些内容足以令学生顺利而兴奋地进入类的学习。
有关类的主要方面将会在学生第一次使用动态内存时(第4章)进一步介绍。在第4章中,我们将对复制构造函数、重载赋值操作符以及析构函数这3个额外元素的需求加以解释。通过第一次使用动态内存来讲授这些OOP方面的知识,能够给学生一个有关动态内存的具体影像,即动态内存是一种能够被使用但是必须在最后被回收的资源。
从概念上来讲,OOP最大的革新在于通过继承实现了软件重用。当然,也可以在数据结构这门课程一开始就介绍继承的概念(例如实现一个集合类作为包类的子类)。然而,过早介绍这些概念也会带来一定的麻烦,学生一下子受困于过多的新概念,会弱化对数据结构基础的理解。因此,将继承放在本课程的最后介绍。但继承的概念也可以在理解了复制构造函数之后(14.1节和14.2节)就开始学习。出于这种想法,有些教师可能希望在堆栈和队列之前讲解第14章。
另一种替代方法是将那些已经了解类的基本知识的学生分离出来,让他们完成继承项目(例如14.2节中的生态系统或14.3节中的游戏引擎),而其他的学生则要先学习类。
模板 模板函数和模板类是标准模板库的一个重要部分,它们便于程序员随意更改容器类中基本数据项的类型。模板类也允许在一个简单的程序中使用多个不同的实例。同样,我们也认为在堆栈(第7章)之前学习并使用模板(第6章)非常重要,这是因为表达式求值是使用堆栈的一个重要应用,它采用了两种类型的堆栈。
迭代器 迭代器是标准模板库的另一个重要部分,它便于程序员遍历容器对象中的数据项(例如集合或包中的元素)。这种迭代器可以是内部的(与容器类成员函数一起实现)或外部的(由容器类的一个独立友元类实现)。我们在讲述第一个容器类时(3.2节的序列)介绍内部迭代器。在第6章中,将会根据需要向包类添加一个内部迭代器。同时,也将会讨论更复杂的外部迭代器,学生应当意识到外部迭代器的优点。总之,迭代器为许多编程项目提供了一个很好的机会,例如实现一个外部包迭代器(第6章),或者利用堆栈实现二叉搜索树的内部迭代器(第10章)。
递归 第一学期的课程不时地向学生介绍递归,但是第一学期的许多例子都是尾递归(tail recursion),尾递归中函数的最后一步就是递归调用,这也许会误导学生错误地认为递归只不过是一个循环。正因为如此,我们在第二学期的课程中尽可能避免过早地使用尾递归。例如,链表遍历和其他链表的操作都可以利用尾递归来实现,但其影响可能会增强对递归的错误印象(当学生在操作含有成千上万个数据项的链表时,应当忘记尾递归链表的操作,以避免遇到潜在的运行时栈溢出)。
因此,在第二学期的课程中,我们将强调除尾递归之外的更多的递归解决方案。第9章“递归思想”中提供了遵循此理念的3个例子。学生将会对其中的两个例子——产生随机分形和穿越迷宫非常感兴趣。在本课程中,我们将在树(第10章)之前讲授递归(第9章),这是因为在递归树算法中递归将会变得至关重要。然而,如果教师希望更多地强调递归的话,可以将这一主题提前,甚至提到第2章之前讲授。
在时间较为充裕的课程中,可以学习高级树项目(第11章)。我们将在这一章中分析递归树算法,解释保持树平衡的重要性——提高最坏情况性能和避免潜在的运行时栈溢出。
查找和排序 第12章和第13章提供了有关查找和排序算法的基础知识。有关查找的内容回顾了有序数组的二分查找,许多学生可能以前已经看到过这些内容。在“查找”一章中还介绍了散列表。在“排序”一章中回顾了简单的二次排序方法,但该章将重点介绍一些快速算法:递归合并排序(最坏情况运行时间为O(n log n))、递归快速排序(平均情况运行时间为O(n log n))和基于树的堆排序(最坏情况运行时间为O(n log n))。此外,该章还对C++标准模板库中的排序函数作了新的介绍。
05 高级项目
本书提供了许多可选的项目,这些项目可以利用更高级的类实现,或者也可以由一些在大型类方面具有扎实背景知识的学生完成。这些特别的高级项目包括以下内容:
·利用动态内存实现的多项式类(4.6节)。
·标准库迭代器,这是学生的包类迭代器的最高级实现(6.3节~6.5节)。
·二叉搜索树迭代器(第10章中的编程项目)。
·利用链表(8.4节)或堆(11.1节)实现的优先队列。
·利用B树(11.2节)实现的集合类。我们对该项目进行了全面的讲解,以便为学生提供一些信息,使他们可以独立实现这个集合类。在本课程中,我们已经成功地指导一些优秀学生以独立工作的方式完成该项目。
·一个继承项目,例如14.2节中的生态系统。
·一个利用抽象基类实现的继承项目,例如14.3节中的游戏基类(利用该类可以非常容易地实现双玩家游戏,例如奥塞罗或者Connect 4)。
·在第15章中提供了一个图类和相关的图算法,这是优秀学生可以独立完成的另一个例子。
06 C++语言特征
C++是一种具有许多高级特征的复杂语言,在第二学期的课程中并不会学习到。但本书将尽力包含我们遇到的一些有关C++特征的全部内容。在本书的第1版中,包含了当年C++的两个新特征:新的bool数据类型和静态成员常量。有关使用静态成员常量的要求在1998标准中已经改变,在本书中也并入了这种改变(现在,常量必须在类定义的内部和外部同时声明)。由1998标准得来的另一个首要的新特征是命名空间的使用,这一内容已经在第2版中并入。对于上述每种情况,旧式编译器也许并不支持这些新特征,对此,我们提供了一些用以解决这一问题的辅助方法(参见附录E,“处理旧式编译器”),以及一些有关下载和安装GNU g++编译器的帮助(参见附录K)。
07 章节次序的灵活性
本书在编写上为教师留有一定的回旋余地,以便他们能够根据特定知识背景的学生的需求来适当调整教学内容,或者先学习所选择的章节。本前言最后的图展示了本书各章之间的相互依赖关系,两个方框之间的连线表明上面方框的内容应当在下面方框的内容之前学习。
这里列出了本书内容讲授次序的一些参考建议:
典型课程 从第1~10章开始,如果学生已经具备C++类的背景知识,则可以跳过第2章的部分内容。大多数章节可在一周之内完成,但第5章(链表)、第6章(模板)、第9章(递归)或第10章(树)则可能需要更多的时间。通常,上述内容可以在13周之内完成,其中包括考试时间以及介绍链表和树的额外时间。余下的几周时间可以讲授第11章的树项目,或者二分查找(12.1节)和排序(第13章)。
重点学习面向对象编程 如果学生在其他课程中已经学会有关排序和查找的内容,那么将会有时间重点学习面向对象编程。前4章可以详细讲授,然后介绍继承类(14.1节)。到此为止,学生将能够完成一个有趣的OOP项目,例如14.2节介绍的生态系统或14.3节中的游戏。接下来讲授基本的数据结构(第5~8章),其中的队列以继承类的形式实现(14.3节)。最后,以递归(第9章)和树(第10章)结束课程,并特别强调递归成员函数。
快速课程 将前3章作为自学内容在第一周之内完成,然后从第4章(指针)开始讲授。这将会在期末留出两到三周的额外时间,以便使学生能够投入更多的时间用以学习查找、排序和其他高级主题(后面的章节依赖关系图中的阴影部分)。
我们也曾以更快的速度讲授该课程,省略堆栈和队列章节的讲授(将这些章节作为学生的自学内容)。
提前讲授递归/提前讲授排序 前一到三周的时间可以用于讲授递归思想的入门。接着首先阅读第1章和第9章的内容,这种方法也许还需要补充额外的递归项目。
如果较早结束递归课程的讲授,教师接下来也可以在介绍C++类之前,讲授二分查找(12.1节)和大部分的排序算法(第13章)。
08 通过Internet获取补充内容
所有读者都可以在www.aw-bc.com/cssupport网址获取本书的以下补充内容:
·源代码 读者可以获取本书中出现的所有C++类、函数和程序。
·勘误表 我们尽可能地不犯错误,但仍难免出现一些疏漏。上述网址中包含了一个已经查出的错误列表,这一列表会根据需要随时更新。如果您在本书中发现任何错误,请发邮件到wkservice@tup.tsinghua.edu.cn,我们将非常感激。
此外,下列补充内容可以提供给已经获得认证的教师。请联系Addison-Wesley销售代表或者发电子邮件到aw.cse@aw.com索取如何获得教辅材料的相关信息。教辅材料包括:
·PowerPoint演讲稿幻灯片
·测验问题
·选定的编程项目的解决方案
·作业示范和实验室练习
·建议的课程提纲...