顺序表表示与实现
线性表
定义与特点
定义:由 \(n(n>=0)\) 个数据特性相同的元素构成的有限序列,称为线性表。
线性表是 \(n(n>=0)\) 个数据元素的有限序列,其中 \(n\) 个数据是相同数据类型的。

线性表ADT
1 2 3 4 5 6 7 8 9 10 11
| ADT List { 数据对象:D={a_i | a_i ∈ ElemSet, i=1,2,…,n, n≥0} 数据关系:S={<a_{i-1},a_i> | a_{i-1},a_i ∈ D, i=2,…,n} 基本操作: InitList(&L) 操作结果:构造一个空的线性表L。 DestroyList(&L) 初始条件:线性表L已存在。 操作结果:销毁线性表L。 …… } ADT List
|
顺序表示与实现
用一组连续的内存单元依次存储线性表的各个元素,也就是说,逻辑上相邻的元素,实际的物理存储空间也是连续的。
1 2 3 4 5 6 7
| #define MAXSIZE 100 typedef int ElemType; typedef struct SeqList{ ElemType data[MAXSIZE]; int length; }SeqList;
|
初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <stdio.h> #include <stdlib.h> #include <string.h>
#define MAXSIZE 100 typedef int ElemType; typedef struct SeqList{ ElemType data[MAXSIZE]; int length; }SeqList;
void InitList(SeqList * L){ L->length = 0; }
int main(int argc, char const *argv[]) { SeqList L; InitList(&L); printf("初始化成功,目前长度占用%d\n", (&L)->length); printf("初始化成功,目前长度占用%d\n", L.length); printf("目前占用内存 %zu 字节\n", sizeof(L.data)); return 0; }
|
对指针理解不深刻写出下面代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <stdio.h> #include <stdlib.h> #include <string.h>
#define MAXSIZE 100 typedef int ElemType; typedef struct SeqList{ ElemType data[MAXSIZE]; int length; }SeqList;
void InitList(SeqList ** L){ *L = (SeqList *)malloc(sizeof(SeqList)); (*L)->length = 0; }
int main(int argc, char const *argv[]) { SeqList * L; InitList(&L); printf("初始化成功,目前长度占用 %d\n", L->length); printf("目前占用内存 %zu 字节\n", sizeof(L->data)); return 0; }
|
- 堆内存:是动态分配的内存,程序运行时通过
malloc
或 calloc
等函数向操作系统申请。这部分内存的生命周期由程序员控制,直到通过 free
函数显式释放为止。如果不释放,会导致内存泄漏。 - 栈内存:内存分配和回收速度非常快,但有大小限制,通常是有限的(受操作系统和硬件的影响)。栈空间是为每个线程分配的,且由系统自动管理。
比较堆和栈内存
- 栈内存:
- 自动管理:当函数返回时,栈上分配的内存会自动回收。
- 空间较小:通常有栈大小限制,一旦超出栈空间就会出现栈溢出错误。
- 局部作用域:仅在函数内部有效,函数执行完毕后即被销毁。
- 堆内存:
- 手动管理:需要程序员显式调用
malloc
申请内存,并用 free
来释放。 - 空间较大:堆空间通常较大,适合分配较大的数据结构或动态长度的数据。
- 生命周期由程序员控制:只要你不显式释放,内存就不会被回收,可能导致内存泄漏。
增加元素
1 2 3 4 5 6 7 8 9
| int addpendElem(SeqList * L, ElemType e){ if(L->length == MAXSIZE){ printf("顺序表已满\n"); return 0; } L->data[L->length] = e; L->length++; return 1; }
|
遍历
1 2 3 4 5 6
| void printlistElem(SeqList * L){ for (int i = 0; i < L->length; ++i){ printf("顺序表里的元素有:%d \n", L->data[i]); } }
|
插入元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| int insertElem(SeqList * L, int index, ElemType e){ if(L->length>=MAXSIZE){ printf("顺序表当前存储的元素已达到最大值,不能插入\n"); return 0; } if(index < 0 || index >= L->length){ printf("插入的位置不符合顺序表,不能插入\n"); return 0; } if(index <= L->length){ for(int i = L->length -1; i>=index-1; i--){ L->data[i+1] = L->data[i]; } L->data[index - 1] = e; L->length++; } return 1; }
|

删除元素

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| int deleteElem(SeqList * L, int index, ElemType * e){ if(L->length <= 0){ printf("顺序表元素为空,不能删除\n"); return 0; } if(index < 0 || index >= L->length){ printf("删除的位置不符合顺序表,不能删除\n"); return 0; } *e = L->data[index-1]; if(index < L->length){ for (int i = index -1; i < L->length; ++i) { L->data[i] = L->data[i+1]; } L->length--; return 1; }
}
|
按值查找
1 2 3 4 5 6 7 8 9 10 11
| int findElem(SeqList * L, ElemType e){ for(int i = 0; i < L->length; i++){ if(L->data[i] == e){ printf("你要查找的元素 %d 在顺序表第 %d 个位置\n", e, i + 1); return i + 1; } } printf("未查找到该元素\n"); return 0; }
|
动态分配内存地址初始化
✅ 方法 1:使用静态数组
如果你使用的就是固定大小的数组(如你原来定义的那样):
1 2 3 4
| typedef struct SeqList{ ElemType data[MAXSIZE]; int length; } SeqList;
|
就不需要也不能再动态分配 data
,所以 InitList
应该改成这样:
1 2 3 4 5
| SeqList * InitList(){ SeqList * L = (SeqList *)malloc(sizeof(SeqList)); L->length = 0; return L; }
|
✅ 方法 2:改成指针 + 动态内存分配
如果你真的想动态分配 data
,应该把结构体改成:
1 2 3 4
| typedef struct SeqList{ ElemType *data; int length; } SeqList;
|
1 2 3 4 5 6
| SeqList * InitList(){ SeqList * L = (SeqList *)malloc(sizeof(SeqList)); L->data = (ElemType *)malloc(sizeof(ElemType) * MAXSIZE); L->length = 0; return L; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| typedef struct SeqList{ ElemType * data; int length; }SeqList;
SeqList * InitList(){ SeqList * L = (SeqList *)malloc(sizeof(SeqList)); L->data = (ElemType *)malloc(sizeof(ElemType) * MAXSIZE); L->length = 0; return L; }
|
问题:
顺序表插入元素的最好时间复杂度是? \(O(1)\)
顺序表插入元素的最坏时间复杂度是? \(O(n)\)
线性表的顺序存储形式(顺序表)有哪些点让你觉得很麻烦?插入删除麻烦