抽象数据类型(ADT, Abstract Data Type):数据模型 + 相关操作。
数据机构(DS, Data Structure):实现ADT的一套算法。
抽象数据类型内部使用数据结构 实现(implementation),封装为统一的 接口(interface) 函数,提供外部用户接口手册以 应用(application) 于实际问题。
接口操作可分为 静态操作 和 动态操作:静态操作仅读取,数据结构内容和组成一般不变,如[]
和 find()
;动态操作需写入,数据结构的局部或整体将改变,insert()
和 remove()
数据存储和组织方式也分为 静态存储 和 动态存储:静态存储的向量,整体创建与销毁数据空间,逻辑和物理存储均连续,支持高效静态操作;动态存储的列表,动态地为数据元素分配和回收物理空间,逻辑连续、物理可不连续,支持高效动态操作。
数组:有限的元素序列。数组 A [ n ] A[n] A[n] = { a 0 , a 1 , . . . a i . . . a n − 1 a_0, a_1,...a_i...a_{n-1} a0,a1,...ai...an−1},其中 a i − 1 a_{i-1} ai−1 是 a i a_i ai 的前驱元素, a 0 a_0 a0 ~ a i − 1 a_{i-1} ai−1 构成 a i a_i ai 前缀。
向量:向量基于数组实现,向量长度 _ s i z e size size 可动态变化,元素可定制为复杂的数据结构。数组元素编号和向量的秩等价,秩 ( R a n k ) (Rank) (Rank) 是向量元素的前驱个数,取值范围是 [ 0 , [0, [0, _ s i z e − 1 ] size-1] size−1]。
typedef int Rank; // 秩
#define DEFAULT_CAPACITY 3 // 默认初始容量
template <typename T>
class Vector {
// 向量模板类
public:
// 构造析构
explicit Vector( int c = DEFAULT_CAPACITY );
~Vector();
// 静态操作
T & Vector<T>::operator[](Rank r) const; // []重载
Rank Vector<T>::find(const T & e, Rank lo, Rank hi) const; // 区间[lo,hi)查找e
// 动态操作
Rank insert( Rank r, const T & e ); // e作为秩为r元素插入
int remove( Rank lo, Rank hi ); // 删除区间[lo, hi)
private:
Rank _size; int _capacity; // 规模、容量
T* _elem; // 数据区
};
template <typename T>
Vector<T>::Vector( int c = DEFAULT_CAPACITY )
{
_elem = new T[ _capacity = c ]; _size = 0; }
template <typename T>
Vector<T>::~Vector()
{
delete [] _elem; }
静态空间管理 是开辟数组 _ e l e m [ ] elem[ ] elem[] 并使用一段地址连续的物理空间存储元素,其中 _ c a p a c i t y capacity capacity 表示总容量, _ s i z e size size 表示当前实际容量。
静态空间管理的容量 _ c a p a c i t y capacity capacity 固定,容易出现上溢、下溢等问题,同时实际开发时难以预测空间的需求量,因此引出空间的动态管理需求。
动态空间管理 比较当前的规模 _ s i z e size size 和容量 _ c a p a c i t y capacity capacity,动态地伸缩数组的容量。
template <typename T>
void Vector<T>::expand() {
if (_size < _capacity) return ; // 尚未满,不扩容
_capacity = max( _capacity, DEFAULT_CAPACITY ); // 保证不低于最小容量
T* oldElem = _elem; // 保存原向量
_elem = new T[ _capacity << 1 ]; // 容量加倍
for (int i = 0; i < _size; i++) // 复制原向量内容
_elem[i] = oldElem[i];
delete [] oldElem; // 释放原向量
}
template <typename T>
void Vector<T>::shrink() {
if ( _size << 2 > _capacity ) return ; // 规模 < (容量/4) 开始收缩
if ( _capacity < DEFAULT_CAPACITY <<= 1) return ; //不致收缩到DEFAULT_CAPACITY以下
T* oldElem = elem; // 保存原向量
_elem = new T[ _capacity >> 1 ]; // 容量减半
for (int i = 0; i < _size; i++) // 复制原向量内容
_elem[i] = oldElem[i];
delete [] oldElem; // 释放原向量
}
template <typename T>
T & Vector<T>::operator[](Rank r) const {
return _elem[r];
}
结合模板和重载 [ ] [] [],可以实现下标读取和修改向量元素。以 V [ r ] V[r] V[r] 为例,返回值 T T T 使得 V [ r ] V[r] V[r] 可以作为右值给其他对象赋值,引用 & \& & 使 V [ r ] V[r] V[r] 可以作为左值被修改。
// 查找
template <typename T>
Rank Vector<T>::find(const T & e, Rank lo, Rank hi) const {
while ((lo < hi--) && (e != _elem[hi])); // 逆向查找
return hi; // hi < lo 表示查找失败
}
template <typename T>
Rank Vector<T>::insert( Rank r, const T & e ) {
expand(); //空间已满,扩容
for ( int i = _size; i > r; i-- ) _elem[i] = _elem[i-1]; //自后向前,后继元素顺次后移一个单元
_elem[r] = e; _size++; //置入新元素并更新容量
return r; //返回秩
}
// 区间删除
template <typename T>
int Vector<T>::remove ( Rank lo, Rank hi ) {
if ( lo == hi ) return 0;
while ( hi < _size ) _elem[lo++] = _elem[hi++]; // [hi, _size)顺次前移hi - lo个单元
_size = lo; //更新规模,直接丢弃尾部[lo, _size = hi)区间
shrink(); // 规模 < (容量/4) 开始收缩
return hi - lo; //返回被删除元素的数目
}
// 删除单个元素
template <typename T>
T Vector<T>::remove( Rank r) {
T e = _elem[r]; // 备份
remove(r, r+1); // 区间删除
return e; // 返回被删除元素
}
列表:采用动态存储策略,元素称为节点,各节点通过指引或引用连接,逻辑构成线性序列。相邻节点互称前驱和后继,前驱和后继存在则唯一,无前驱节点称为首节点,无后继节点称为末节点。
// ListNode.h
#define Posi(T) ListNode*
template <typename T>
struct ListNode {
T data;
Posi(T) pred; // 前驱
Posi(T) succ; // 后继
ListNode() {
}; // 构造header和trailer
ListNode(T e, Posi(T) p = NULL, Posi(T) s = NULL)
: data{
e}, pred{
p}, succ{
s} {
}; // 默认构造器
Posi(T) insertAsPred(T const& e); // 前插
Posi(T) insertAsSucc(T const& e); // 后插
};
#include "ListNode.h" //引入列表节点类
template <typename T>
class List {
//列表模板类
public:
// 构造析构
List();
~List();
// 静态操作
T& operator[] ( Rank r ) const; // 按秩查找
Posi(T) find ( T const& e ) const; // 按值查找
// 动态操作
Posi(T) insertA ( Posi(T) p, T const& e ); // e当作p的后继插入(After)
Posi(T) insertB ( Posi(T) p, T const& e ); // e当作p的前驱插入(Before)
T remove ( Posi(T) p ); // 删除节点p
private:
int _size; // 规模
Posi(T) header; Posi(T) trailer; // 哨兵
};
template <typename T>
List<T>::List() {
header = new ListNode<T>; // 头哨兵
trailer = new ListNode<T>; // 尾哨兵
header->succ = trailer; header->pred = NULL;
trailer->pred = header; trailer->succ = NULL;
_size = 0; // 记录规模
}
template <typename T>
List<T>::~List() {
while ( 0 < _size ) remove ( header->succ ); //反复删除首节点,直至列表变空
delete header; delete trailer; // 释放头尾哨兵
}
template <typename T>
T & List<T>::operator[](Rank r) const {
Posi(T) p = first(); // 从首节点出发
while (0 < r--) p = p->succ; // 顺数第r个节点
return p->data;
}
template <typename T>
Posi(T) List<T>::find(T const & e, int n, Posi(T) p) cosnt {
while (0 < n--) // 自后向前逐个比对
if (e == ( p = p->pred )->data)
return p;
return NULL; // 失败
}
template <typename T>
Posi(T) List<T>::insertBefore(Posi(T) p, T const &e)
{
_size++; return p->insertAsPred(e); }
template <typename T>
Posi(T) ListNode<T>::insertAsPred ( T const& e ) {
// this节点是p
Posi(T) x = new ListNode ( e, pred, this ); // x->succ=p; x->pred=p->pred;
pred->succ = x; pred = x; // p->pred->succ=x; p->pred=x;
return x; // 返回新节点的位置
}
template <typename T>
T List<T>::remove(Posi(T) p) {
T e = p->data;
p->pred->succ = p->succ;
p->succ->pred = p->pred;
delete p; _size--; return e;
}