静态链表
- 定义:用数组描述的链表叫做静态链表。
- 实现:使每个数据元素由两个数据域组成,一个相当于单链表中的数据域,用来存放数据元素,另一个相当于单链表中的指针域,用来存放元素后继在数组中的下标(游标)。
静态链表存储结构
#define MAXSIZE 1000
typedef struct
{
ElemType data; //数据域
int cur; //游标,为0时无指向
}Component,StaticLinkList[MAXSIZE];
- 备用链表:数组中未被使用的数组元素称为备用链表。
- 准备:对数组的第一个元素和最后一个元素做特殊处理。使下标为0的元素的cur存放备用链表的第一个结点的下标,最后一个元素的cur存放第一个有数值的元素下标(即单链表中的头结点),链表为空时为0。
- 初始化:
int InitList(StaticLinkList space)
{
for(int i = 0; i < MAXSIZE-1; i++)
space[i].cur = i+1; //遍历“指针”
space[MAXSIZE].cur = 0; //静态链表为空,最后一个元素的cur为0
return 1;
}
静态链表的插入
-
准备:数组链表不能像动态链表直接借用c语言的malloc()和free()函数。实现一个新的函数,使数组第一个元素的cur指向备用链表的下一个(此时的第二个)结点的下标。
-
Malloc_SLL()函数:
int Malloc_SLL(StaticLinkList space)
{
int i = space[0].cur; //返回备用链表的第一个结点下标
if(space[0].cur) //存在空闲结点
space[0].cur = space[i].cur; //下标改为空闲结点所指向的结点下标
return i;
}
- 插入ListInsert:思路同单链表,指针域变为结点下标。
int ListInsert(StaticLinkList L, int i, ElemType e)
{
int j;
int k = MAX_SIZE - 1; //声明k,初始化为最后一个元素的下标
if (i < 1 || i > ListLength(L) + 1)
return 0;
j = Malloc_SSL(L); //获取可插入的空闲结点的下标
if ( j )
{
L[j].data = e; //赋值给数据域
for(int l = 1; l <= i - 1; l++) //找到第i个元素之前的位置
k = L[k].cur;
L[j].cur = L[k].cur;
L[k].cur = j; //cur下标的调换
return 1;
}
return 0;
}
静态链表的删除
- 准备: 实现一个函数,将要删除的结点回收到备用链表。
- Free_SSL()函数:
void Free_SSL(StaticLinkList space, int k)
{
space[k].cur = space[0].cur; //把第一个元素的cur赋值给要删除的结点
space[0].cur = k; //把k的下标赋值给第一个元素的cur
}
- 删除ListDelete:
int ListDelete(StaticLinkList L, int i)
{
int k;
int j;
if (i < 1 || i > ListLength(L))
return 0;
k=MAX_SIZE - 1;
for (j = 1; j <= i - 1; j++) //找到要删除的元素的前一个位置
k = L[k].cur;
j = L[k].cur; //获取要删除的元素
L[k].cur=L[j].cur; //将要删除的元素所指向的结点下标赋值给前一元素的后继
Free_SSL(L, j); //删除元素
return 1;
静态链表的优缺点
- 在插入和删除时,只需修改游标。(同单链表指针域)
- 表长难以确定,需要足够大的空间
循环链表
- 定义:将单链表中的终端结点的指针域由空指针改为指向头结点,这种头尾相接的单链表就叫做循环链表。
- 判断:p->next不等于头结点时,循环未结束。
- 合并:通过尾指针合并两个循环链表A和B:
p = rearA->next; //保存A的头节点
rearA->next = rearB->next->next; //将B的第一个结点赋值给A的最后一个结点的后继
q = rearB->next; //保存B的头结点
rearB->next = p; //将A的头结点赋值给B的最后一个结点的后继
free(q); //释放B的头结点
双向链表
- 定义:在单链表的每个结点中,设置一个指向前驱结点的指针域则为双向链表。
- 双向链表也可以有循环。
双向链表的存储结构
typedef struct DulNode
{
ElemType data;
struct DuLNode *prior; //直接前驱指针
struct DuLNode *next; //直接后继指针
}DulNode, *DuLinkList;
p->next->prior = p = p->prior->next;
//后继的前驱等于前驱的后继等于自己本身
双向链表的插入顺序
//在p后插入s
s->prior = p; //把p赋值给s的前驱
s->next = p->next; //把p后一个结点赋值给s的后继
p->next->prior = s; //把s赋值给p的后一个结点的前驱
p->next = s; //把s赋值给p的后继
双向链表的删除顺序
//删除p
p->prior->nex t= p->next; //把p的后继赋值给p的前一个结点的后继
p->next->prior = p->prior; //把p的前驱赋值给p的后一个结点的前驱
free(p); //释放p