为什么要写这篇博客?
嵌入式开发中,在很多的环境下无法使用官方库,可以自己写数据结构,进行使用。
顺序表:在连续的内存中,存入一系列结点的存储单元。示意图如下所示。
上图可以看到:存储地址是连续的,表示可以通过(某一结点的地址+偏移量)直接访问其他结点。
顺序表的特点:随机访问(通过表头元素地址和元素的标号,在O(1)的时间复杂度找到指定元素)
顺序表的不足:删除和插入都需要移动大量的元素
顺序表基本操作:构造、插入、扩容、查找、删除、遍历。以下是目录:
- 顺序表的构造
- 顺序表的创建
- 表的初始化
- 结点插入
- 表的扩容
- 结点查找
- 结点删除
- 表的遍历
- 释放内存
顺序表的构造
- 顺序表的创建
- 正如上图中看到的,需要变量记录,表的最大长度size和当前状态下表内数据个数。
- 其次,需要一个指针变量指向内存地址data。
typedef struct Vector {
// 最大容量和当前顺序表个数
int size,length;
// 用来指向存储元素的数据
int *data;
} Vector;
- 表的初始化
- 分别为表中的变量赋值
- 为顺序表的数据存储分配内存
void init(Vector *vector, int size) {
vector->size = size;
vector->length = 0;
// 这里分配的内存是存放数据数组的内存
vector->data = (int*)malloc(sizeof(int)*size);
}
结点插入
- 判断插入位置是否合法
- 判断顺序表是否已满,是否需要扩容(主要是因为size一开始就固定了)。
- 将目标位置及之后的元素后移一位
- 将待插入的元素插入到目标位置
int insert(Vector *vector, int loc, int value) {
// 判断形参位置信息是否符合
if(loc < 0 || loc > vector->length){
return ERROR;
}
// 判断是否需要扩容
if(vector->length >= vector->size){
// return ERROR;
expand(vector);
}
// 从表尾逐步向后移动
for(int i = vector->length; i > loc; i--){
vector->data[i] = vector->data[i-1];
}
// 添加新元素
vector->data[loc] = value;
// 长度加一
vector->length++;
return OK;
}
插入元素(复杂度分析):
表的扩容
- 将原来的元素存储到临时存储空间
- 扩大原来的存储空间
- 将存储空间里的数据元素复制到新的存储空间里
- 释放临时存储空间
void expand(Vector *vector){
int *old_data = vector->data;
vector->size = vector->size * 2;
vector->data = (int *)malloc(sizeof(int) * vector->size);
for(int i = 0; i < vector->length; i++){
vector->data[i] = old_data[i];
}
free(old_data);
}
结点查找
- 从下标为0的元素开始依次枚举所有元素
- 发现和value相同的值,则返回他的index
- 枚举没找到目标元素则返回-1
int search(Vector *vector, int value) {
for (int i = 0; i < vector->length; i++) {
if (vector->data[i] == value) {
return i;
}
}
return -1;
}
查找方法的时间复杂度:
结点删除
- 判断线标是否合法(if)
- 将目标下标之后的元素前移一位(for)
- 更新顺序表的长度(length--)
int delete_node(Vector *vector, int index) {
if (index < 0 || index >= vector->length) {
return ERROR;
}
for (int i = index + 1; i < vector->length; ++i) {
vector->data[i - 1] = vector->data[i];
}
vector->length = vector->length - 1;
return OK;
}
删除方法时间复杂度:
表的遍历
- 从下标为0的元素开始遍历
- 输出所有的元素值
void print(Vector *vector) {
for (int i = 0; i < vector->length; i++) {
if (i > 0) {
printf(" ");
}
printf("%d", vector->data[i]);
}
printf("\n");
}
释放内存
- 在创建链表指针的时候申请一部分需要释放
- 在创建数据存储单元的时候需要释放一部分
void clear(Vector *vector) {
free(vector->data);
free(vector);
}
用顺序表完成以下题目:
代码如下:
int main() {
Vector *a = (Vector *)malloc(sizeof(Vector));
init(a, 5);
int n, col, data;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d%d", &col, &data);
insert(a,col,data);
}
clear(a);
return 0;
}
第二道题
int main() {
Vector *a = (Vector *)malloc(sizeof(Vector));
init(a, 20);
int m, t,index,value,feiwu;
scanf("%d", &m);
for(int i = 0; i < m; i++){
scanf("%d", &t);
switch(t){
case 1 :
scanf("%d%d", &index, &value);
feiwu = insert(a,index,value);
break;
case 2 :
scanf("%d", &index);
feiwu = delete_node(a,index);
break;
case 3 :
scanf("%d", &value);
feiwu = search(a,value);
break;
case 4 :
print(a);
break;
}
}
free(a);
return 0;
}