我们在学数据结构的时候,经常遇到的一个概念就是抽象数据类型(Abstract Data Type),简称 ADT。
维基百科中的定义是:抽象数据类型是计算机科学中具有类似行为的特定类别的数据结构的数学模型,或者具有类似语义的一种或多种程序设计语言的数据类型。
从这段定义来看,非常地费解,其实我们只需要抓住核心。核心就是接口和实现的分离。我们在使用一个 ADT 的时候,只需要和接口进行交互,而不必关心接口中的实现细节。同样,数据也是隐藏不可见的,也需要通过接口进行交互。
也就是说接口是数据类型唯一的交互方式,除此之外,用户无法接触到 ADT 的数据以及实现细节。
举个例子,以栈举例,如果我们不将栈设计成 ADT,那么用户在使用栈的时候,可能就需要自己创建一个数组来存储栈中的数据,通过调用一些方法来实现栈的功能。但这势必需要用户了解栈的原理,以及数据存储的细节。ADT 会做一个良好的封装,用户只需要了解每个接口的功能,调用对应的接口实现自己想要的逻辑即可。
我们来看一下 C++ Primer 当中实现的栈的例子。
首先,我们需要知道栈一共有哪些接口,大概有如下这么几个:
- 创建空栈
- 可添加数据到栈顶
- 可从栈顶弹出数据
- 可查看栈是否为空
- 可查看栈是否已满
然后,我们遵守 C++中面向对象的设计思路,将它封装在一个类当中。首先我们来定义这个类:
#ifndef STACK__H_
#define STACK__H_
typedef unsigned long Item;
class Stack {
private:
enum {MAX=10};
Item items[MAX];
int top;
public:
Stack();
bool isempty() const;
bool isfull() const;
bool push(const Item &item);
bool pop(Item &item);
};
#endif
我们来看下这个定义,会发现,其中的数据都被设定成了private
,也就是用户无法直接访问到数据。只能通过public
的接口进行交互,也无须关心其中的实现细节,可以当做黑盒使用。
最后, 我们再来看下 C++ Primer 当中给出的实现:
#include "stack.h"
Stack::Stack() {
top = 0;
}
bool Stack::isempty() const {
return top == 0;
}
bool Stack::isfull() const {
return top == MAX;
}
bool Stack::push(const Item &item) {
if (top < MAX) {
items[top++] = item;
return true;
}
return false;
}
bool Stack::pop(Item &item) {
if (top > 0) {
item = items[--top];
return true;
}
return false;
}