一、线性表的链式存储—链表
在链式存储中,每个存储节点不仅包含有所存元素本身的信息(称之为数据域),而且包含有元素之间逻辑关系的信息,即前驱节点包含有后继节点的地址信息,这称为指针域,这样可以通过前驱节点的指针域方便地找到后继节点的位置,提高数据查找速度。 若一个节点中的某个指针域不需要任何节点,则仅它的值为空,用常量NULL表示。
在线性表的链式存储中,为了便于插入和删除运算的实现,每个链表带有一个头节点,并通过头节点的指针唯一标识该链表。
由于链表的每个结点带有指针域,从存储密度来讲,这是不经济的。所谓存储密度是指结点数据本身所占的存储量和整个结点结构中所占的存储量之比,即:存储密度=节点数据本身占用的空间/节点占用的空间总量。
一般地,存储密度越大,存储空间的利用率就越高。显然,顺序表的存储密度为1,而链表的存储密度小于1。例如,若单链表的结点数据均为整数,指针所占的空间和整数相同,则单链表的存储密度为50%。若不考虑顺序表中的空闲区,则顺序表的存储空间利用率为100%。
在单链表中,由于每个节点只包含有一个指向后继节点的指针,所以当访问过一个节点后,只能接着访问它的后继节点,而无法访问它的前驱节点。
另一种可以采用的方法是: 在每个节点中除包含有数值域外,设置有两个指针域,分别用以指向其前驱节点和后继节点,这样构成的链接表称之为线性双向链接表,简称双链表。
二、单链表
在单链表中,假定每个节点类型用LinkList表示,它应包括存储元素的数据域data和存储后继元素位置的指针域next。
LinkList类型的定义如下:
typedef struct LNode //定义单链表节点类型
{ ElemType data;
struct LNode *next; //指向后继节点
} LinkList;
1. 插入节点和删除节点操作
插入操作是将值为x的新节点插入到单链表的第i个节点的位置上。先在单链表中找到第i-1个节点,再在其后插入新节点。
单链表插入和删除节点的过程如下图所示。
插入操作语句描述如下: