目录
一、数据结构之顺序表(Array List)
1.1 顺序表
顺序表是一种线性表的存储结构,它使用数组来存储元素,这些元素在内存中是连续存储的。顺序表可以快速定位元素的位置,但在插入和删除元素时可能需要移动大量元素,因为元素的存储位置是固定的。
1.2 顺序表与链表的区别
- 顺序表:顺序表使用数组顺序存储元素,元素在内存中是连续存储的。
- 链表:链表使用指针链接存储元素,元素在内存中可以是不连续的,通过指针相互连接。
1.3 线性表与数组的区别
- 线性表:线性表是一种逻辑结构,表示元素之间的线性关系,可以使用数组或链表来实现。
- 数组:数组是一种物理存储结构,表示一组相同类型的元素按照一定顺序在内存中连续存储。
在C语言中,数组的长度是固定的,定义时需要指定长度,而线性表的长度是动态可变的,可以根据需要进行动态调整。
二、 顺序表的分类
静态顺序表和动态顺序表是顺序表的两种不同实现方式,它们在内存管理和灵活性方面有所不同。
2.1 静态顺序表
2.1.1 定义
静态顺序表是指在程序运行前就确定了大小的顺序表,它的存储空间是静态分配的,一旦分配了大小,就不能动态改变。静态顺序表通常使用数组来实现,数组的长度是固定的,定义时需要指定大小。
2.1.2 结构体定义
其中包含一个固定大小为 10 的整型数组 x 和一个整型变量 size,用来表示静态顺序表中的元素和当前存储的元素个数
2.2 动态顺序表
2.2.1 定义
动态顺序表是指在程序运行时根据需要动态分配内存空间的顺序表。动态顺序表通常使用指针和动态内存分配来实现,可以根据需要动态增加或减少存储空间。
2.2.2 结构体定义
其中包含一个指向动态数组的指针 data,以及两个变量
size
和capacity
,用来表示动态顺序表中的有效数据个数和当前容量。动态顺序表可以根据需要动态调整大小,从而提供灵活性和效率。
三、顺序表的接口实现
3.1 初始化顺序表
3.2 插入元素
3.2.1 头插
顺序表的头插操作是指在顺序表的开头位置插入一个新元素。
- 检查顺序表是否已满,如果已满则可能需要扩容。
- 将顺序表中的所有元素向后移动一个位置,为新元素腾出空间。
- 在顺序表的开头位置插入新元素。
- 更新顺序表的大小。
3.2.2 尾插
顺序表的尾插操作是指在顺序表的末尾插入一个新元素。
- 检查顺序表是否已满,如果已满则可能需要扩容。
- 将新元素插入到顺序表的最后一个位置。
- 更新顺序表的大小。
3.2.3 指定位置插入元素
顺序表的在任意位置插入操作指的是在顺序表中的指定位置插入一个元素。
移动元素:将插入位置及其后面的元素向后移动一个位置,为新元素腾出空间。
插入新元素:在指定位置插入新元素。
更新大小:增加顺序表的大小,即元素个数加一。
3.3 删除元素
3.3.1 头删
顺序表的头删操作指的是从顺序表的头部删除一个元素。
移动元素:将顺序表中的元素向前移动一个位置,覆盖被删除的元素。
更新大小:减少顺序表的大小,即元素个数减一。
释放空间:如果需要释放内存空间,可以在删除元素后进行内存释放操作。
3.3.2 尾删
顺序表的尾删操作指的是从顺序表的尾部删除一个元素。
直接删除尾部元素:将顺序表中最后一个元素删除。
更新大小:减少顺序表的大小,即元素个数减一。
释放空间:如果需要释放内存空间,可以在删除元素后进行内存释放操作。
3.3.3 删除指定位置的元素
顺序表的任意位置删除操作指的是在顺序表中删除指定位置的元素。
移动元素:将指定位置后面的元素向前移动一个位置,覆盖被删除的元素。
更新大小:减少顺序表的大小,即元素个数减一。
释放空间:如果需要释放内存空间,可以在删除元素后进行内存释放操作。
3.4 扩容
在顺序表中,当插入元素时发现当前容量不足以容纳更多元素时,需要进行扩容操作。
-
确定扩容策略:在顺序表中,常见的扩容策略是将当前容量扩大一定倍数,通常是两倍。这样可以减少频繁扩容的次数,提高效率。
-
分配新空间:当需要扩容时,需要分配一个更大的内存空间来存储更多元素。这通常通过动态内存分配函数如
realloc
来实现。 -
数据迁移:将原有数据从当前内存空间复制到新的更大空间中。这确保了之前存储的数据不会丢失。
-
释放旧空间:在数据迁移完成后,释放原有的内存空间,以防止内存泄漏。
四、顺序表的优缺点
4.1 优点
- 支持随机访问,时间复杂度为O(1)。
- 内存连续,利于CPU缓存命中,访问效率高。
4.2 缺点
- 插入和删除操作可能需要移动大量元素,时间复杂度为O(n)。
- 扩容操作可能导致大量元素的复制,影响性能。