1.线性表
线性表是n个具有相同特征的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、队列、字符串…
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理存储时,通常以数组和链式结构的形式存储。
2.顺序表
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删改查。
顺序表一般可以分为:
- 静态顺序表:使用定长数组存储。顺序表的容量,实在静态时期确定(编译期间,代码里写死)
typedef struct SeqList {
int array[100]; // 容量是 100
int size; // 顺序表实际存储的数据个数
} SeqList;
- 动态顺序表:使用动态开辟的数组存储。容量在动态时期确定(运行时期)
typedef struct SeqList {
int *array; // 指向动态开辟的数组
int capacity; // 容量
int size; // 1. 有效数据的个数
// 2. 尾插时,可用位置的下标
} SeqList;
接口实现:静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。
// 初始化
void SeqListInit(SeqList *ps, int capacity);
// 销毁
void SeqListDestroy(SeqList *ps);
增、删、改、查
// 尾插
void SeqListPushBack(SeqList *ps, int v);
// 头插
void SeqListPushFront(SeqList *ps, int v);
// 根据 pos 下标做插入
void SeqListInsert(SeqList *ps, int pos, int v);
// 尾删
void SeqListPopBack(SeqList *ps);
// 头删
void SeqListPopFront(SeqList *ps);
// 根据 pos 下标做删除
void SeqListErase(SeqList *ps, int pos);
// 查找
int SeqListFind(SeqList *ps, int v);
// 更新
int SeqListModify(SeqList *ps, int pos, int v);
// 删除第一个遇到的 v
void SeqListRemove(SeqList *ps, int v);
// 删除所有遇到的 v
void SeqListRemoveAll(SeqList *ps, int v);
注意:
- 中间/头部的插入删除,时间复杂度为O(N);
- 增容需要申请新空间,拷贝数据,释放旧空间;
- 增容一般是呈 2 倍的增长,势必会有一定的空间浪费。