在前章中的顺序结构中,每个数据元素只需存数据元素信息就可以了,而在链式结构中,除了要存数据元素信息外,还要存储它的后继元素的存储地址。
因此,为了表示每个数据元素ai与其直接后继数据元素ai+1之间的逻辑关系,对数据元素ai来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置)。我们把存储数据信息的域称为数据域,把存储直接后继位置的域称为指针域。指针域中存储的信息称做指针或链。这两部分信息组成数据元素ai的存储映像,称为结点(Node)。
n个结点链结成一个链表,即为线性表(a1,a2,......,an)的链式存储结构,因为此链表的每个结点中只包含一个指针域,所以叫做单链表。单链表正是通过每个结点的指针域将线性表的数据元素按其逻辑次序链接在一起,如下图所示:
在单链表中,我们可以用C语言结构指针来描述。
typedef struct Node
{
ElemType data;
struct Node *next;
}Node;
typedef struct Node *LinkList; //定义LinkList
1.单链表的创建
单链表整表创建的算法思路如下:
1)声明一结点p和计数器变量i;
2)初始化一空链表L;
3)让L的头结点的指针指向NULL,即建立一个带头结点的单链表;
4)循环:
生成一新结点赋值给p;
随机生成一数字赋值给p的数据域p->data;
将p插入到头结点与前一新结点之间。
代码算法实现如下:
void CreateListHead(LinkList *L, int n)
{
LinkList p;
int i;
*L = (LinkList)malloc(sizeof(Node)); //先建立一个带头结点的单链表
(*L)->next = NULL;
for(i = 0; i < n; i++)
{
p = (LinkList)malloc(sizeof(Node)); //生成新结点
p->data = 0;
p->next = (*L)->next;
(*L)->next = p; //插入到表头
}
}
在这段算法代码里,我们其实用的是插队的办法,就是始终让新结点在第一的位置。实际上我们还可以把新结点插在终端结点的后面。
void CreateListTail(LinkList *L, int n)
{
LinkList p,r;
int i;
*L = (LinkList)malloc(sizeof(Node)); //整个线性表
r = *L; //r为指向尾部的结点
for(i = 0; i < n; i++)
{
p = malloc(sizeof(Node)); //生成新结点
p->data = 0;
r->next = p; //将表尾终端结点的指针指向新结点
r = p; //将当前的新结点定义为表尾终端结点
}
r->next = NULL; //表示当前链表结束
}
2.单链表的整表删除
当我们不用单链表时,我们需要把它销毁,也就是在内存中将它释放掉,以便留出空间给其他程序使用。
单链表整表删除的算法思路如下:
1)声明一结点p和q;
2)将第一个结点赋值给p;
3)循环:
将下一结点赋值给q;
释放p;
将q赋值给p。
代码算法实现如下:
int ClearList(LinkList *L)
{
LinkList p,q;
p = (*L)->next; //p指向第一个结点
while(p) //没有到表尾
{
q = p->next;
free(p);
p = q;
}
(*L)->next = NULL; //头结点指针域为空
reutrn OK;
}