静态链表
用数组描述的链表叫做静态链表,这种描述方法另名游标实现法。
#define MAXSIZE 1000 /* 存储空间初始分配量 */
/* 线性表的静态链表存储结构 */
typedef struct
{
ElemType data;
int cur; /* 游标(Cursor) ,为0时表示无指向 */
} Component,StaticLinkList[MAXSIZE];
数组第一个元素cur用来存放备用链表(空闲空间)第一个结点的下标。
数组最后一个元素cur用来存放第一个插入元素的下标,相当于头结点。(当整个链表为空时,则为0)
静态链表的插入操作
/* 若备用空间链表非空,则返回分配的结点下标,否则返回0 */
int Malloc_SSL(StaticLinkList space)
{
int i = space[0].cur; /* 当前数组第一个元素的cur存的值 */
/* 就是要返回的第一个备用空闲的下标 */
if (space[0]. cur)
space[0]. cur = space[i].cur; /* 由于要拿出一个分量来使用了, */
/* 所以我们就得把它的下一个 */
/* 分量用来做备用 */
return i;
}
/* 在L中第i个元素之前插入新的数据元素e */
Status ListInsert(StaticLinkList L, int i, ElemType e)
{
int j, k, l;
k = MAXSIZE - 1; /* 注意k首先是最后一个元素的下标 */
if (i < 1 || i > ListLength(L) + 1)
return ERROR;
j = Malloc_SSL(L); /* 获得空闲分量的下标 */
if (j)
{
L[j].data = e; /* 将数据赋值给此分量的data */
for(l = 1; l <= i - 1; l++) /* 找到第i个元素之前的位置 */
k = L[k].cur;
L[j].cur = L[k].cur; /* 把第i个元素之前的cur赋值给新元素的cur */
L[k].cur = j; /* 把新元素的下标赋值给第i个元素之前元素的ur */
return OK;
}
return ERROR;
}
插队,只需要影响头元素的第一个备用节点,将其+1,再修改插入位置的前后元素的cur,即可不影响其他元素地完成插入操作。
静态链表的删除操作
/* 删除在L中第i个数据元素 */
Status ListDelete(StaticLinkList L, int i)
{
int j, k;
if (i < 1 || i > ListLength(L))
return ERROR;
k = MAXSIZE - 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 OK;
}
/* 将下标为k的空闲结点回收到备用链表 */
void Free_SSL(StaticLinkList space, int k)
{
space[k].cur = space[0].cur; /* 把第一个元素的cur值赋给要删除的分量cur */
space[0].cur = k; /* 把要删除的分量下标赋值给第一个元素的cur */
}
头元素cur改为指向备用链表第i个结点的下标。
尾元素cur改为指向第一个元素的下标(如果删除的是第一个元素)。
获得静态链表L中数据元素的个数
/* 初始条件:静态链表L已存在。操作结果:返回L中数据元素个数 */
int ListLength(StaticLinkList L)
{
int j=0;
int i=L[MAXSIZE-1].cur;
while(i)
{
i=L[i].cur;
j++;
}
return j;
}
静态链表的优缺点
插入删除操作时不需要移动元素,改进了顺序存储结构中插入和删除操作需要移动大量元素的缺点。
但没有解决连续存储分配带来的表长难以确定的问题、
且失去了链式存储结构随机存取的特性。
本质上是一种为了给没有指针的高级语言设计的一种实现单链表能力的方法。
循环链表
将单链表中终端结点的指针端由空指针改为指向头结点,就使整个单链表行程一个环,这种头尾相接的单链表称为单循环链表,简称循环链表
合并两个循环链表的方法:
p=rearA->next; /* 保存A表的头结点,即① */
rearA->next=rearB->next->next; /* 将本是指向B表的第一个结点(不是头结点)*/
/* 赋值给reaA->next,即② */
q=rearB->next;
rearB->next=p; /* 将原A表的头结点赋值给rearB->next,即③ */
free(q); /* 释放q */
双向链表
双向链表是在单链表的每个结点中,再设置一个指向其前驱结点的指针域。
/*线性表的双向链表存储结构*/
typedef struct DulNode
{
ElemType data;
struct DuLNode *prior; /*直接前驱指针*/
struct DuLNode *next; /*直接后继指针*/
} DulNode, *DuLinkList;
插入操作时,需要更改两个指针的变量
s - >prior = p; /*把p赋值给s的前驱,如图中①*/
s -> next = p -> next; /*把p->next赋值给s的后继,如图中②*/
p -> next -> prior = s; /*把s赋值给p->next的前驱,如图中③*/
p -> next = s; /*把s赋值给p的后继,如图中④*/
删除时同理
p->prior->next=p->next; /*把p->next赋值给p->prior的后继,如图中①*/
p->next->prior=p->prior; /*把p->prior赋值给p->next的前驱,如图中②*/
free(p); /*释放结点*/