单链表的定义和表示
线性表链式存储结构的特点是:用一组任意的存储单元存储存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)。因此,为了表示每个数据元素ai与其后继数据元素ai+1之间的逻辑关系,对数据元素ai来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置)。这两部分信息组成数据元素ai的存储映像,称为结点(node)。它包括两个域:其中存储数据元素信息的域称为数据域;存储直接后继存位置的域称为指针域。指针域中存储的信息称作指针或链。n个结点链结成一个链表,即为线性表的链式存储结构。又由于此链表的每个结点中只包含一个指针域,故又称线性链表或单链表。
用单链表表示线性表时,数据元素之间的逻辑关系是由结点中的指针指示的。换句话说,指针为数据元素之间的逻辑关系的映像,则逻辑上相邻的两个数据元素其存储的物理位置不要求紧邻,由此,这种存储结构为非顺序映像或链式映像。
通常将链表画成下图形式,这是因为在使用链表时,关心的只是它所表示的线性表中数据元素之间的逻辑顺序,而不是每个数据元素在存储器中的实际位置。
由上述可见,单链表可由头指针唯一确定,在C语言中可用“结构指针”来描述:
// -----单链表的存储结构------
typedef struct LNode
{
ElemType date; //结点的数据域
struct LNode *next; //结点的指针域
}LNode,LinkList; //LinkList为指向结构体LNode的指针类型
一般情况下,为了处理方便,在单链表的第一个结点之前附设一个结点,称之为头结点。下图是单链表增加头结点后。
下面对首元结点、头结点、头指针三个容易混淆的概念加以说明。
(1)首元结点是指链表中存储第一个数据元素ai的结点。如上两图中的“ZHOU”。
(2)头结点是在首元结点之前附设的一个结点,其指针域指向首元结点。头结点的数据域可以不存储任何信息,也可以存储与数据元素类型相同的其他附加信息。例如,当数据元素为整数型时,头结点的数据域中可存放该线性表的长度。
(3)头指针是指向链表中第一个结点的指针。若链表设有头结点,则头指针所指结点为线性表的头结点;若链表不设头结点,则头指针所指结点为该线性表的首元结点。
链表增加头结点的作用如下。
(1)便于首元结点的处理
增加了头结点后,首元结点的地址保存在头结点的指针域中。则对链表的第一个数据元素的操作与其他数据元素相同,无需进行特俗处理
(2)便于空表和非空表的统一处理
当链表不设头结点时,假设L为单链表的头指针,他应该指向首元结点,则当单链表为长度n为0的空表时,L指针为空(L==NULL)。
在顺序表中,由于逻辑上相邻的两个元素在物理位置上紧邻,则每个元素的存储位置都可从线性表的起始位置计算得到。而在单链表中,各个元素的存储位置都是随意的。然而,每个元素的存储位置都包含在其直接前驱结点的信息之中。假设p是指向单链表中第i个数据元素的指针,则p->next是指向第i+1个个数据元素的指针。换句话说,若p->date=ai.则p->next->date=ai+1。由此,单链表是非随机存取的存储结构,要取得第i个数据元素必须从头指针出发顺链进行寻找。也称为顺序存取的存取结构。因此,其基本操作的实现不同于顺序表。