在电影的例子中,数据形成了一个项目列表,其中每一项包含一个片名(C的字符串)和等级(int值)。C中没有符合这个需求的基本类型,所以需要定义一个结构来表示每个项目,然后设计一此方法来把一系列结构链接成一个列表。
实际上 ,我们使用C的功能设计了一种符合需要的新的数据类型。但是我们的做法并不系统。
现在我们将用更为系统的方法来定义数据类型。
假设您想定义一个新的数据类型。首先,您需要提供存储数据的方式,可能是通过设计一个结构。第二,需要提供操作数据的方式。比如,考虑films2.c程序。它用一系列链接在一起的结构来保存信息,还提供了添加信息和显示信息的代码。但是这个程序并没有明确的表明我们在创建一个新的类型。应该怎么做呢?
计算机科学已经研究出一种定义新类型的成功的方法。这种方法使用3个步骤来完成从抽象到具体的过程:
1、为类型的属性和可对类型执行的操作提供一个抽象的描述。这个描述不应受任何特定实现的约束,甚至不应受任何特定编程语言的约束。这样一种正式的抽象数据描述被称为抽象数据类型(ADT)。
2、开发一个实现该ADT的编程接口。即说明如何存储数据并描述用于执行所需操作的函数集合。比如,在C中您可能同时提供一个结构的定义和用来操作该结构的函数的原型。这些函数对用户自定义类型的作用和C的内置运算符对C的基本类型的作用一样。想要使用新类型的人,可以使用这个接口来进行编程。3、编写代码来实现这个接口。当然, 这一步至关重要,但是使用这种新类型的程序员无须了解实现的细节。
我们通过一个例子来了解这个过程。让我们重新完成电影列表的例子。
变得抽象
基本上关于电影工程所需的就是一个项目列表,每个项目包含一个影片名和一个等级。您需要能向列表末尾添加新的项目,并且能显示列表的内容。让我们把满足这些需求的抽象类型称为“列表(list)”。一个列表应有哪些属性呢?显然,列表应该能够保存项目序列。即,列表能够保存多个项目,并且这些项目以某种方式排列,从而能够谈及列表中的第一项或第二个项目或最后一个项目。而且,列表类型应该支持诸如向列表添加一个项目之类的操作。下面是一些有用的操作:
*把列表初始化为空列表。
*向列表末尾添加一个项目。
*确定列表是否为空。
*确定列表是否已满。
*确定列表中有多少个项目。
*访问列表中每一个项目以执行某些任务,比如显示项目。
对此工程来说,不需要对列表进行其他操作,但是通常的列表操作还包括如下内容:
*在列表的任何位置插入一个项目。
*从列表中删除一个项目。
*取出列表中的一个项目(不改变列表)。
*替换列表中的一个项目。
*在列表中搜索一个项目。
非正式但抽象的列表定义是:它是一个能够保存项目序列并且可以对其应用任何前面的操作的数据对象。这个定义没有说明什么样的项目才能存储在列表中。它并未指出是否应该使用数组或链接的结构集或其他数据形式来保存这些项目。它并未指出使用何种方法来实现诸如获取列表中的元素个数之类的操作。这些都是留给实现的细节。
为了使例子更简单,我们采用一种简化的列表作为抽象数据类型,它只包含电影工作所需的属性。表17.1是此类型的一个总结 :
列表类型总结
类型名称: | 简单列表 |
类型属性: | 可保存一个项目序列 |
类型操作: | 把列表初始化为空列表 |
确定列表是否为空 | |
确定列表是否已满 | |
确定列表中有多少个项目 | |
向列表末尾添加一个项目 | |
访问列表中每一个项目 | |
清空列表 |
下一步是为简单列表ADT开发一个C语言接口。
构造接口
简单列表的接口有两个部分。第一部分描述数据如何表示,第二部分描述实现ADT操作的函数。接口的设计应尽可能的与ADT描述密切保持一致。因此,应该用某种通用的Item类型来进行表达,而不是用诸如int或struct film之类的专用类型。这样做的方法之一就是使用C的typedef工具将Item定义为所需类型:
#define TSIZE 45 /*存放片名的数组大小*/
struct film {
char title[TSIZE];
int rating;
};
typedef struct film Item;
然后可以在其余的定义中使用Item类型。如果以后需要其他形式数据的列表,您可以重新定义Item类型,而使其余接口定义保持不变。
定义了Item之后,您需要决定如何存储这种类型的项目