链表中第一个结点的存储位置叫做头指针。
单链表的第一个结点前附设一个结点,称为头结点。
一、头结点与头指针的异同
①头指针:头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针;头指针具有标识作用,所以常用头指针冠以链表的名字;无论链表是否为空,头指针均不为空。头指针是链表的必要元素。
②头结点:头结点是为了操作的统一和方便而设立的,放在第一元素的结点之前,其数据域一般无意义(也可存放链表的长度);有了头结点,在第一元素结点前插入结点和删除第一结点的操作就与其它结点的操作统一了。头结点不一定是链表必须要素。
二、线性表链式存储结构代码描述
//线性表的单链表存储结构
typedef struct Node
{
int data;
struct Node *next;
}Node;
typedef struct Node *LinkList; //定义LinkList
1.单链表的读取
获得链表第i个数据的算法思路:
①声明一个结点p指向链表第一个结点,初始化j从1开始;
②当j<i时,遍历链表,让p的指针向后移动,不断指向下一结点,j累加1;
③若到链表末尾p为空,则说明第i个元素不存在;
④否则查找成功,返回结点p的数据。
//初始条件:顺序线性表L已存在,1<=i<=ListLength(L)
//操作结果:用e返回L中第i个数据元素的值
int GetElem(LinkList L, int i, ElemType *e)
{
int j;
LinkList p;
p = L->next; //p指向L的第一个结点
j = 1;
while(p && j<i)
{
p = p->next;
j++;
}
if(!p || j>i)
return 0;
*e = p->data;
return 1;
}
2.单链表的插入
单链表第i个数据插入结点的算法思路:
①声明一结点p指向链表第一个结点,初始化j从1开始;
②当j<i时,遍历链表,让p的指针向后移动,不断指向下一结点,j累加1;
③若链表末尾p为空,则说明第i个元素不存在;
④否则查找成功,在系统中生成一个空结点s;
⑤将数据元素e赋给s->data;
⑥单链表的插入标准语句s->next=p-next;p->next=s;
⑦返回成功。
初始条件:顺序线性表L已存在,1<=i<=ListLength(L)
int ListInsert(LinkList *L, int i, ElemType e)
{
int j;
LinkList p,s;
p = *L;
j = 1;
while(p && j<i)
{
p = p->next;
j++;
}
if(!p || j>i)
return 0;
s = (LinkList)malloc(sizeof(Node));
s->data = e;
s->next = p->next;
p->next = s;
return 1;
}
3.单链表的整表创建
单链表整表创建的算法思路:
①声明一结点p和计数器变量i;
②初始化一空链表L;
③让L的头结点的指针指向NULL,即建立一个带头结点的单链表;
④循环:
生成一新结点赋值给p;
随机生成一数字赋给p的数据域p->data;
将p插入到头结点与前一新结点之间。
//随机生成n个元素的值,建立带表头结点的单链线性表L(头插法)
void CreateListHead(LinkList *L, int n)
{
LinkList p;
int i;
srand(time(0)); //初始化随机数种子
*L = (LinkList)malloc(sizeof(Node));
(*L)->next = NULL;
for(i=0; i<n; i++)
{
p = (LinkList)malloc(sizeof(Node));
p->data = rand()%100+1;
p->next = (*L)->next;
(*L)->next = p;
}
}
//尾插法创建单链表
void CreateListTail(LinkList *L, int n)
{
LinkList p,r;
int i;
srand(time(0)); //初始化随机数种子
*L = (LinkList)malloc(sizeof(Node));
r = *L;
for(i=0; i<n; i++)
{
p = (LinkList)malloc(sizeof(Node));
p->data = rand()%100+1;
r->next = p;
r = p;
}
r->next = NULL;
}
4.单链表的整表删除
单链表整表删除的算法思路:
①声明一结点p和q;
将第一个结点赋给p;
③循环:
将下一结点赋值给q;
释放p;
将q赋值给p;
//初始条件:顺序线性表L已存在,操作结果:将L重置为空表
int ClearList(LinkList *L)
{
LinkList p,q;
p = (*L)->next;
while(p)
{
q=p->next;
free(p);
p = q;
}
(*L)->next = NULL;
return 1;
}
若线性表需要频繁查找,很少进行插入和删除操作时,宜采用顺序存储结构。若需要频繁插入和删除时,宜采用单链表结构。
当线性表中的元素变化较大或者根本不知道有多大时,最好用单链表结构;如果已知线性表的大致长度,用顺序存储结构效率会高很多。