线性表:包含n个元素的有序序列,元素的信息由使用场景决定。线性表的表现形式有线性表和链表两种形式,两者的却别在于内存空间的连续性。
1.顺序表:开辟连续的内存空间存储元素。在实现形式上分为两种:静态顺序表(使用定长数组)、动态顺序表(使用动态内存分配),使用动态内存分配的方式使得代码的可维护性提升,该方式优于静态顺序表的存储方式。
![](https://i-blog.csdnimg.cn/blog_migrate/a33c0e65ee24573f9f1c235880fd26c7.png)
顺序表的构造:
typedef struct SeqList
{
ElemType *base;
size_t capacity;
size_t size;
}SeqList;
由上顺序表的构造形式可以看出,顺序表包含三部分内容:存储数据的空间base(使用动态内存分配为顺序表开辟内存空间),容量capacity,当前大小size。
顺序表的相关操作:插入(按值/按位置)、删除(按值/按位置)、查找 、修改、排序、显示。
顺序表的优缺点:
优点:便于数据查找
缺点:空间连续,在中间/头部插入删除数据时,需要将之后的所有数据进行移动。
扩容一般是以两倍的形式增长,会造成空间的浪费,同时扩容也可能存在数据拷贝的问题。
2.链表:物理存储上非连续,但逻辑连续的存储结构,逻辑上的连续使用指针的指向实现。
链表的结构按类别:①单向、双向 ②带头、不带头 ③循环、非循环,以上三种组合起来共8中链表结构。
①单向、双向
![](https://i-blog.csdnimg.cn/blog_migrate/11aedf801562f25e0480cc617f5817c0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ea806ca89caf13e1235c70f97b9d0f70.png)
②带头、不带头
![](https://i-blog.csdnimg.cn/blog_migrate/3c5c7cae1904d89fa9df5867ca470b66.png)
![](https://i-blog.csdnimg.cn/blog_migrate/8d826c47ddcd965ab70fd38b21568c20.png)
③循环、非循环
![](https://i-blog.csdnimg.cn/blog_migrate/c5918a6ac6fbae78dd8942945e957682.png)
![](https://i-blog.csdnimg.cn/blog_migrate/123bf301e4001b921df45c0733b84e81.png)
常用的链表结构:无头单向非循环链表,带头双向循环链表
<1>无头单向链表的构造:
typedef struct SListNode
{
ElemType data;
struct SListNode *next; //后继
}SListNode;
<2>带头双向循环链表的构造:
typedef struct DCListNode
{
ElemType data;
DCListNode *next; //后继
DCListNode *prev; //前驱
}DCListNode;
①无头单向非循环链表
②带头双向循环链表
<1>无头单向线性链表:由一个个的节点连接组成,每个节点包含:数据域、指针域,链表之间的逻辑关系通过指针的指向体现。
<2>双向循环链表:也是由一个个节点组成,但是与 线性链表不同,该节点具有两个指针变量,分别用于指向它的前驱和后继,同时最后一个节点的后继指向头结点,头结点的前驱指向最后一个节点。
注:使用链表函数接收参数的定义,接收时使用二级指针的目的:修改外部的结构体头指针的指向。一般在
总结:使用二级指针的目的是为了修改一级指针。