抽象数据类型
抽象数据类型(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 前缀。
接口
// Array.h
#define ElemType int
#define MaxSize 50
typedef struct {
ElemType data[MaxSize]; // 顺序表的元素
int length; // 顺序表的当前长度
}SqList; // 顺序表的类型定义
// 静态操作
int LocateElem(SqList L, ElemType e);
// 动态操作
bool Insert(SqList &L, int i, ElemType e);
bool Delete(SqList &L, int i, ElemType &e);
实现
1. 空间管理
顺序表是开辟数组 data[ ]
并使用一段地址连续的物理空间存储元素,其中 MaxSize
表示总容量, length
表示当前实际容量。
#define MaxSize 50
typedef struct {
ElemType data[MaxSize]; // 顺序表的元素
int length; // 顺序表的当前长度
}SqList; // 顺序表的类型定义
顺序表的容量 Maxsize
固定,容易出现上溢、下溢等问题,同时实际开发时难以预测空间的需求量。
3. 静态操作
- 按秩查找:
L.data[i];
- 按值查找:
int LocateElem(SqList L, ElemType e)
{
for (int i=L.length-1; i>=0; i--)
if (L.data[i]==e)
return i+1; // 下标为 i 的元素值等于e, 返回其位序 i+1
return 0;
}
4. 动态操作
- 插入
bool Insert(SqList &L, int i, ElemType e)
{
if (i<1||i>L.length+1) // 判断 i 的范围是否有效
return false;
if (L.length>=MaxSize) // 当前存储空间已满,不能插入
return false;
for (int j = L.length; j>=i; j--) // 自后向前,后继元素顺次后移一个单元
L.data[j] = L.data[j-1];
L.data[i-1] = e; L.length++;
return true;
}
- 删除:
bool Delete(SqList &L, int i, ElemType &e)
{
if (i<1||i>L.length) // 判断 i 的范围是否有效
return false;
e = L.data[i-1];
for (int j=i; j<L.length; j++) // 自前向后,后继元素顺次前移一个单元
L.data[j-1] = L.data[j];
L.length--;
return true;
}
链表
链表:采用动态存储策略,元素称为节点,各节点通过指引或引用连接,逻辑构成线性序列。相邻节点互称前驱和后继,前驱和后继存在则唯一,无前驱节点称为首节点,无后继节点称为末节点。
接口
// ListNode.h
#define ElemType int
struct LNode;
typedef struct LNode* LinkList; // 链表
typedef struct LNode* Position; // 链表结点
typedef struct LNode{ // 定义单链表结点类型
ElemType data; // 数据域
Position next; // 指针域
};
void Insert(LinkList L, int i, ElemType e);
void Delete(LinkList L, int i, ElemType &e);
Position Get(LinkList L, int i);
Position Find(LinkList L, ElemType e);
实现
1. 空间管理
链表结点 LNode
包含数据域 data
和指针域 next
,其中 data
表示数据元素, next
表示后继节点的地址。
struct LNode;
typedef struct LNode* LinkList; // 链表
typedef struct LNode* Position; // 链表结点
typedef struct LNode{ // 定义单链表结点类型
ElemType data; // 数据域
Position next; // 指针域
};
2. 静态操作
- 按秩查找:
Position GetElem(LinkList L, int i)
{
int j=1;
Position p=L->next;
if (i==0) return L; // 若i等于0, 返回头结点
if (i<1) return NULL; // 若i无效,返回NULL
while (p!=NULL && j<i) { // 查找第i个结点
p=p->next; j++;
}
return p;
}
- 按值查找:
Position LocateElem(LinkList L, ElemType e)
{
Position p=L->next;
while (p!=NULL && p->data!=e) // 查找值为e的结点
p=p->next;
return p;
}
3. 动态操作
- 插入:
void Insert(LinkList L, int i, ElemType e);
{
Position p=GetElem(L,i-1); // 插入位置前驱结点
Position s=malloc(sizeof( struct Node ));
if (s==NULL) {
printf("Out of Space!!!");
return 0;
}
s->data=e;
s->next=p->next;
p->next=s;
}
- 删除:
void Delete(LinkList L, int i, ElemType &e);
{
Position p=GetElem(L,i-1); // 删除位置前驱结点
Position q=NULL;
q=p->next; e=q->data;
p->next=q->next;
free(q);
}