链表
线性表的链式储存结构
有很多个结点,每个结点都有一个指针头,左后一个结点的指针为空,通常设置为null或者^表示,第一个结点称作为头结点
| 头指针 | 头结点 |
|---|---|
| 头指针是指链表指向第一个结点的指针,若链表有头结点,则指向头结点的指针 | 头结点是为了操作的统一和方便而设立的,放在第一元素的结点之前,其数据域一般无意义(也可以存放链表的长度) |
| 头指针具有标识作用,所以常用头指针冠以链表的名字 | 有了头结点,在对第一元素结点前插入结点和删除第一结点,其操作与其他结点的操作就统一了 |
| 无论链表是否为空,头指针均不为空,头指针是链表的必要元素 | 头结点不一定是链表必须要素 |
单链表

空链表

链表结构
1 | typedef struct Node{ |
(1) 获取当前元素
初始条件:顺序线性表*L*存在,*1<=i<=ListLength(L)*,操作结果:用*e*返回*L*中第*i*个元素的值
1 | Status GetElem(LinkList L, int i, ElemType *e) |
从头开始找,直到第个元素为止由于这个算法的时间复杂度取决于1的位置,当
i=1时,则不需要遍历,而i=n时则遍历n-1次可以因此最坏情况的时间复杂度为O(n)。
(2) 链表插入
需要先把需要插入的数据的头指向原来的后一位,然后再将原来的前一位指向插入的数据的内容,否则操作相反会导致后一位没有上级
1 | //正确的插入方式 |
初始条件:顺序线性表*L*已存在,*1<=i<=ListLength(L)*操作结果:在*L*中第*i*个位置之前插入新的数据元素*e*,*L*的长度加*1*
1 | Status ListInsert(LinkList *L, int i, ElemType e) |
(3) 链表删除
初始条件:顺序线性表*L*已存在,*1<=i<=ListLength(L)*操作结果:删除在*L*中第*i*个位置的数据元素,并用*e*返回值,*L*的长度减*1*
1 | Status ListDelete(LinkList *L, int i, ElemType *e) |
时间复杂度为
O(n),对于插入或删除数据越频繁的操作,单链表的效率优势就越是明显