顺序表是一组连续的存储单元来依次存储线性表中的结点,而链表是用一组任意的存储单元来存放线性表中的结点,这组存储单元可不连续分布在内存中的任何位置上。因此,链表中结点的逻辑顺序与存储顺序不一定相同。为了体现各结点存储单元之间的逻辑关系,再存储每个结点的同时,还必须存储与之联系的相邻结点的地址信息,这个信息称为指针或链。在C语言中,可以用指针实现。根据不同的链接方式,链表可以分为单链表,循环链表和双向链表。这里先介绍单链表的建立。
单链表
在单链表中,每个结点只有一个指针域指向下一个结点的地址,因此每个结点包括数据域和指针域。
第1个结点a1无前趋,故应设一个头指针head存储第1个结点的地址,也是链表的起始地址。由于最后一个结点a4无后继,因此它的指针域(指向下一个结点的地址)为空。
用C语言描述单链表的结点结构如下:
typedef int datatype;
typedef struct node //结点类型定义
{
datatype data;//结点的数据域类型
struct node *next;//结点指针域类型
} linklist;
建立单链表
为了建立一个能具体操作的单链表,假设结点的数据类型为字符型,下面介绍两种建立字符链表的方法。
1)头插法建表
头插法是按结点的逆序方法逐渐将结点插入到链表的头部,如图
头插法程序设计如下:
linklist *CreatList1()
{
char ch;
linklist *head,*p;
head=NULL;//开始链表的头指针为空
ch=getchar();// 输入最后一个结点字符值
while(ch!='#')//输入为#时结束增加结点
{
p=(linklist *)malloc(sizeof(linklist));//分配内存
p->data=ch;
p->next=head;//使新增结点的指针域的值等于原链表的头指针head值,使其指向
//原链表的头结点,达到新节点链到链表的头部目的
head=p;
ch=getchar();
}
return head;//返回头指针
}
头插法建立链表的算法简单,但是生成链表的结点顺序与输入顺序想反,但人们习惯使用下面的尾插法。
2)尾插法建表
尾插法按结点的顺序逐渐将结点插入到链表尾部。
尾插法程序设计如下:
linklist *CreatList2()
{
char ch;
linklist *head;
linklist *p;//p始终指向新分配的结点空间
linklist *e;//e始终指向新建链表的尾结点
head=NULL;
e=NULL;
ch=getchar();
while(ch!='#')
{
p=(linklist *)malloc(sizeof(linklist));
p->data=ch;
if(head==NULL) head=p;
else e->next=p;
e=p;
ch=getchar();
}
if(e!=NULL) e->next=NULL;
return head;//返回头指针
}
下节会继续介绍链表的查询,插入,删除。