65# 抽象数据类型与子程序 #

8.1 抽象数据类型

抽象数据类型(ADT):属性(数据和操作)明确地与特定实现分离的容器。

  • 应用(或用户)层是特定问题中的数据的视图。
  • 逻辑(或抽象)层是数据值(域)和处理它们的操作的抽象视图。
  • 实现层明确表示出了存放数据项的结构,并用程序设计语言对数据的操作进行编码。这个视图用明确的数据域和子程序表示对象的属性。这一层涉及了数据结构,即一种抽象数据类型中的复合数据域的实现。

数据结构:一种抽象 数据类型中的复合数据域的实现。
容器(container): 存放和操作其他对象的对象。

8.2 栈

  栈和队列是抽象复合结构,二者经常被同时提及,栈是种抽象复合结构,只能从一端访问栈中的元素。可以在第一个位置插人元素,也可以删除第一个元素。 这种设计模拟了日常生活中的很多事情。会计师称它为LIFO.即后进先出(Last In First Out)的缩写。自助餐厅的餐具架就有这种属性:我们只能取顶上的碟子。当取走一个碟子后,下面的碟子就出现在了顶层。
  另一种描述栈的访问行为的说法是删除的项总是在栈中时间最短的项目。从这个角度观察栈就更加抽象。插人操作没有任何约束;整个LIFO行为都体现在删除操作上。
  栈的插入和删除操作有了个惯用语,插人操作叫作Push (推进),删除操作叫作Pop (弹出)。我们把项目推进栈,从栈中弹出项目。栈没有长度属性,所以没有返回栈中项目个数的操作。我们需要的是确定栈是否为空(Is Empty)的操作,因为当栈空的时候再弹出项目会出错。

8.3 队列

  队列也是种抽象结构,队列中的项目从一端人,从另端出。会计师称之为FIFO、即先进先出(Fist In First Out)的缩写。插入操作在队列的rear(尾部)进行,删除操作在队列的front(头部)进行。
  另一种描述队列的访问行为的说法是删除的总是在队列中时间最长的项目。

8.4 列表

  列表有三个属性特征:项目是同构的,项目是线性的,列表是变长的。线性的意思是,每个项目除了第一个都有一个独特的组成部分在它之前,除了最后一个也都有一个独特的组成部分在它之前后。   数组是内嵌结构,,列表是抽象结构。   列表也可以被形象化为链式结构,链式结构以节点的概念为基础。
  链式结构(linked structure):一个将数据项和找到下一项位置的信息保存到同一容器的实现方法。

8.5 树

8.5.1 二叉树

  • 二叉树(binary tree):具有唯一起始节点(根节点)的抽象复合结构,其中每个节点可以有两个子女节点,根节点和每个节点之间都有且只有一条路径。
  • 根(root):树中唯一的开始节点。
  • 叶节点(leaf node):没有子女的树节点。

8.5.2 二叉检索树

  任何节点的值都要大于它的左子树中的所有节点的值,并且要小于它的右子树中的所有节点的值。

  • 在二叉检索树中搜索
      如果current指向一个节点,那么info(current)指的就是这个节点中的用户数据,left(current)指向的是current的左子树的根节点。null是一个特殊值,说明指针指向空值。因此,如果一个指针是null,那么这个子树就是空的。
  • 构造二叉检索树
  • 输出二叉检索树中的数据

8.5.3 其他操作

8.6 图

  • (graph):由一组节点和一组把节点相互连接起来的边构成的数据结构。
  • 顶点(vertex):图中的节点。
  • 边(弧)(edge(arc)):表示图中的两个节点的连接的顶点对。
  • 无向图(undirected graph):其中的边没有方向的图。
  • 有向图(directed graph(digraph)):其中的边是从一个顶点指向另一个顶点(或同一个顶点)的图。
  • 邻顶点(adjancent vertice):通过边连接起来的两个顶点。
  • 路径(path):连接图中两个顶点的一系列顶点。

8.6.1 创建图

列表、栈、队列和树都是可容纳元素的容器。用户根据特定的问题选择最合适的容器。不被纳人检索过程的算法是没有固定语义的:栈返回的元素是在其中停留时间最少的元素;队列返回的是在其中停留时间最长的元素。队列和树返回的信息都是被请求的。然而不同的是,在图中定义的算法可以解决实际的问题。首先我们来探讨创建一个图,然后讨论利用图可以解决的问题。

  许多信息可以被呈现在图上:顶点、边和权值。让我们利用航班连接数据来把这些结构可视化为一张表。表8-3中的行和列标有城市的名字。单元格中的零代表从该行城市到该列城市不存在可以直达的航班。表格中的数值为从该行城市至该列城市的公里数。

创建-一个表格需要以下操作:

●在表格中添加一个顶点
●在表格中添加一条边
●在表格中添加一个权值

8.6.2 图算法

  • 深度优先搜索
  • 广度优先搜索
  • 单源最短路搜索

8.7 子程序

8.7.1 参数传递

  • 参数列表(parameter list):程序中两部分之间的通信机制。
  • 形参(parameter):列在子程序名后的括号中的标识符。
  • 实参(argument):子程序调用中列在括号中的标识符。

8.7.2 值参与引用参数

值参(value parameter):由调用单元传入实参的副本(写在留言板上)的形参。 引用参数(reference parameter):由调用单元传入实参的地址(卸载留言板上)的形参。

第九章 面向对象设计与高级程序设计语言

  面向对象的设计方法是用叫作对象的独立实体生成解决方案的问题求解方法,对象由数据和处理数据的操作构成。面向对象设计的重点是对象以及它们在问题中的交互。一.旦收集到了问题中的所有对象,它们就能构成问题的解决方案。

9.1.1 面向对象

  • 对象(object):在问题背景汇总相关的事物或实体。
  • 对象类(object class)或(class):一组具有相似属性和行为的对象的描述。
  • (fisld):类中的特定项,可以是数据或子程序。
  • 方法(method):定义了类的一种行为的特定算法。

9.1.2 设计方法

  • 集体讨论
  • 过滤
  • 场景
    • 封装(encapsulation):把数据和动作集中在一起,使数据和动作的逻辑属性与它们的实现细节分离。
  • 责任算法

我们提出的分解过程有四个阶段。 集体讨论(头脑风暴)是确定问题中的类的第个阶段。在过滤这个阶段中,将回顾集体讨论阶段确定的类,看哪些类是可以合并的以及还缺少哪些类。过滤阶段保留下来的类将在下一个阶段仔细研究。 场景阶段将确定每个类的行为。由于每个类只对自己的行为负责,所以我们称类的行为为责任。这个阶段探讨的是“如果....将会怎 么样”的问题,以确保所有的情况都被分析到。当每个类的责任都确定后,它们将被记录下来,同时记录的还有它们必须与之协作(交互)才能履行责任的类的名字。 最后是责任算法阶段,这个阶段将为列出的所有类的责任编写算法。CRC卡就是用来记录这一阶段的类信息的工具。

9.2 翻译过程

编译器(compiler):把用高级语言编写的程序翻译成机器码的程序。 解释器(interpreter):输入用高级语言编写的程序,指导计算机执行每个语句指定的动作的程序。 字节码(bytecode):编译Java源代码使用的标准机器语言。

9.3 程序设计语言的范型

  • 命令式范型
    • 面向过程的范型
    • 面向对象的范型
  • 声明式范型
    • 函数式范型
    • 逻辑编程

9.4 高级程序设计语言的功能性

在高级语言中,选择和迭代操作非常简单,但子程序和参数传递则较为复杂。

9.4.1 布尔表达式

一个布尔表达式可以是:

  • 一个布尔变量
  • 一个算术表达式加一个关系运算符,再加一个算术表达
  • 一个布尔表达式加一个布尔运算符,再加一一个布尔表达式

迄今为止,在示例中,变量存放的都是数值。布尔变量是内存中的一一个地址,由存放true或false的标识符引用。

  • 布尔表达式( Boolean expression):一个标识符序列,标识符之间由相容的运算符分隔,求得的值是true或false。

9.4.2 数据归类

  • 强类型化(strong typing):每个变量都有一个类型, 只有这种类型 的值才能存储到该变量中。
  • 数据类型(datatype):一组值以及能够应用于这种类型的值的基本操作集合的说明。

数据类型

数据是表示信息的物理符号。在计算机内部,数据和指令都是二进制位的组合。计算机能够执行一条指令,是因为这条指令的地址被载人了程序计数器,而指令被载入了指令寄存器。被执行的位组合同样可以表示整数、实数、字符或布尔值,关键看计算机如何解释位组合。

大多数高级语言都固有四种数据类型,即整数、实数、字符和布尔型。

整数

整数数据类型表示的是一个整数值的范围,这个范围由表示整数值的字节数决定。有些高级语言提供几种范围不同的整数类型,允许用户根据特定问题选择最适合的类型。

实数

实数数据类型表示的是特定精度的数的范围,与整数数据类型一样,这个范围由表示实数值的字节数决定。许多高级语言有两种大小的实数。应用于实数的操作与应用于整数的一样。但在对实数应用关系运算符时要小心,因为实数通常不精确。

字符

第3章介绍过,表示ASCII字符集中的字符需要-一个字节,表示Unicode字符集中的字符则需要两个字节。ASCII字符集包括英语字符,是Unicode字符集的子集。对字符进行算术运算是毫无意义的,许多强类型化的语言都不允许进行这种运算。但比较字符却是有意义的,所以可以对字符进行关系运算。在字符的关系运算中,“小于”和“大于”的意思是这个字符在字符集中“在.....之前” 和“在....之后”。例如,字符‘A’小于‘B',字符‘B’小于‘C',等等。字符‘1’小于字符‘2',‘2’小于‘3’,等等。如果要比较‘A’和“1’, 必须在使用的字符集中查找这两个字符间的关系。

布尔型

布尔数据类型只有两个值——true和false。还可以为布尔变量指定一个布尔表达式。

整数、实数、字符和布尔型称为简单数据类型或原子数据类型,因为每个值都是独立的,不能再分割。上一章讨论了 复合数据类型,即由一组值构成的数据类型。字符串是一种具有复合数据类型的特征的数据类型,但通常被看作简单数据类型。

字符串

字符串是一个字符序列,在某些语言中这个序列通常被看作一个数据值。

声明

  • 声明(declaration):把变量、动作或语言中的其他实体与标识符关联起来的语句,使程序员可以通过名字引用这些项目。
  • 保留字(reserved word): 一种语言中具有特殊意义的字,不能用它作为标识符。
  • 区分大小写(case sensitive):大写字母和小写字母被看作是不同的;两个拼写方法相同但大小写形式不同的标识符被看作是两个不同的标识符。

9.4.3 输入/输出结构

在非强类型语言中,输入的格式决定了类型。如果输人出现在引号之间,则它被假定为一个字符串,并以字符串的形式存储。如果输人的是一个数字, 它将被存储为数字。

输出语句创建字符流。输出语句中列出的项目可以是文字值或变量名。文字值是直接在输出语句中写的数字或字符串(或任何语句)。一次处理一个将要输出的值,从而找到标识符或文字的类型。类型确定了如何解释位模式。如果该类型是字符串,则将字符写人输出流。如果该位模式为数字,则该数字将被转换为表示数字的字符,并将字符输出。

在强类型语言中,不管输人输出语句的语法或输人输出流在哪儿,处理的关键在于数据类型,数据类型确定字符是如何被转换为位模式(输人)以及如何被转换为字符(输出)。在非强类型语言中,输人的格式决定了位模式是如何转换的。

9.4.4 控制结构

  • 控制结构:确定程序中的其他指令的执行顺序的指令

嵌套逻辑

在任何控制语句中被执行或跳过的语句可以是简单的语句或块(一组语句),对于这些语句没有任何限制。事实上,被跳过或重复的语句可以包含一个控制结构。选择语句可以在循环结构中被嵌套。循环结构可以在选择语句中被嵌套。选择和循环语句可以在子程序中被嵌套,而子程序可以在循环或选择结构中被嵌套。

异步

  • 异步(asynchronous): 不与计算机中的其他操作同时发生;换句话说,与计算机的动作不同步。

异步处理也叫作事件驱动处理。换句话说,这样的处理是被程序指令序列以外发生的事件所控制。
异步处理经常被用在Java和VB.NET中,但是很少被其他语言所使用。

9.5 面向对象语言的功能性

9.5.1 封装

  • 封装(encapsulation);实施信息隐蔽的语言特性。
  • 对象类或类(问题求解阶段) ( object class or class ( problem solving phase)):属性和行为相似的一组对象的说明。
  • 对象(问题求解阶段)(object (problem- solving phase)):与问题背景相关的事物或实体。
  • 对象(实现阶段)( object (implementation phase):类的一个实例。
  • 类(实现阶段)(class (implementation phase)):对象的模式。

9.5.2 类

从语法上来说,类像前面介绍的记录,它们都是异构复合数据类型。但记录通常被认为是被动结构,只是近年来才采用子程序作为域。而类则是主动结构,一直都把子程序 用作域。操作类的数据域的唯一方式是通过类中定义的方法(子程序)。

  • 实例化(instantiate): 创建类的对象。

算法声明类的对象只能通过类的子程序(称为方法)访问类的域。
默认情况下,类中的域是私有的,也就是说,除非一个类的某 个域被标识为public (公有),否则任何其他对象都不能访问这个类的对象的域(无论是数据还是方法)。如果一个类想让其他类的对象调用自己的方法,就必须明确地声明这个方法是public的。Person 类中的方法被标记为public,以便用程序可以调用。

9.5.3 继承

继承是面向对象语言的一种属性, 即一个类可以继承另一个类的数据和方法。这种关系是一种is-a关系。超类是被继承的类,派生类是继承的类。类构成了继承的体系结构。在这种体系结构中,所处的层次越低,对象越专门化。下级的类会继承其父类的所有行为和数据。

  • 继承(inheritance):类获取其他类的属性(数据域和方法)的机制。

继承通过允许应用程序使用已经被测试过的类和从一一个类中继 承应用所需的属性来促进重用。其他必要的属性和方法可以在之后加人派生类中。

9.5.4 多态

假设Person类和Student类都具有名为Print和Initialize的方法。在Person类中,这个方法将输出Person类中定义的地址,在Student类中,该方法则输出Student类中定义的地址。这两个方法名字相同,但实现不同。程序设计语言处理这种明显二义性的能力叫作多态性。语言如何知道调用单元调用的是哪个Print方法还是Initialize方法呢?调用单元将把类的方法应用于类的一一个实例,应用这个方法的对象的类可以确定使用的是Print 或Initialize的哪个版本。

  • 多态( polymorphism):一种语言的继承体系结构中具有两个同名方法且能够根据对象应用合适的方法的能力。

9.6 过程设计与面向对象设计的区别

在面向过程的版本中,列表被呈现为传递给子程序的记录,以便子程序可以对其操作。操作它的数据结构和子程序是用户程序的一部分。
在面向对象的版本中,类对象的实现通过封装实现对用户的隐藏。

Copyright © 2024 罗雪峰
Powered by .NET 8.0 on Kubernetes