链表
链表的概念
一种常见的重要的数据结构,是动态的进行存储分配的一种结构。用数组存放数据时,需先定义固定的数组长度,链表则根据需要开辟内存单元。
定义
链表是一种物理存储上非连续,数据元素的逻辑顺序通过链表中的指针链接次序,实现的一种线性存储结构。
如图为一种链表(单向链表)的结构:
head 1249 1356 1475 1021
特点
- 链表有一个“头指针”变量 ,如图head,它存放一个地址,该地址指向一个元素。链表中每一个元素称为结点,每个结点都包括两部分:(1)存储数据元素的数据域(2)存储下一个节点地址的指针域。head 指向第1个元素,第1个元素又指向第2个元素,直到最后一个元素,该元素不再指向其他元素,它称为“表尾”,它的地址部分放一个“NULL”(空地址),链表到此结束 。
- 链表中各元素在内存中的地址可以是不连续的 。
- 作用:通过结点把离散的数据链接在一起,组成一个表。
链表的构成
链表由一个个结点构成,每个结点一般采用结构体的形式组织
结点
数据域:存放各种实际的数据。
指针域:存放下一结点的首地址。(指针域中储存的信息称为指针或链)
struct student
{
//数据域
int num;
char name[20];
//指针域
struct student *next;//next是指针变量,指向结构体变量
};
头指针
链表中第一个结点的存储位置叫做头指针。
NULL
线性链表的最后一个结点指针为“空”(用“NULL”或“^"表示)
头结点
为了更加方便地对链表进行操作,在单链表的第一个结点前附设一个结点,称为头结点。
头结点的数字域可以不储存任何信息,也可以储存如线性表的长度等附加信息。
头指针与头结点异同
链表与数组的对比
数组中的成员及链表中的结点
链表
通过节点把离散的数据链接成一个表,通过对节点的插入和删除操作从而实现对数据的存取。链表中各元素在内存中的地址可以不连续。
数组
通过开辟一段连续的内存来存储数据,有起始地址。
单链表的读取
获得链表第i个数据
算法思路
1.声明一个结点p指向链表第一个结点, 初始化j从1开始;
2.当j<i时,就遍历链表, 让p的指针向后移动,不断指向下一结点, j累加1;
3.若到链表末尾p为空,则说明第i 个元素不存在;
4.否则查找成功,返回结点p的数据。
代码
Status GetElem (LinkList L,int i,ElemType *e)
{
int j;
LinkList p; //声明一结点p
p=L->next; //让p指向链表L的第一个结点
j=1; //计数器
while(p&&j<i) //p不为空或者计数器j还没有等于i时,循环继续
{
p=p->next; //让p指向下一个结点
++j;
}
if(!p||j>i)
return ERROR;//第i个元素不存在
*e=p->data; //取第i个元素的数据
return OK;
}
单链表的插入与删除
链表第i个数据插入或删除结点
单链表的插入
s->next=p->next;
p->next=s;
算法思路
1.如果查找成功,生成一个空结点s;
2.将数据e赋值给s->data;
3.再执行s->next=p->next;p->next=s;
4.最后返回。
代码
Status GetElem (LinkList *L,int i,ElemType e)
{
int j;
LinkList p,s;
p=*L;
j=1; //计数器
while(p&&j<i) //p不为空或者计数器j还没有等于i时,循环继续
{
p=p->next; //让p指向下一个结点
++j;
}
if(!p||j>i)
return ERROR;//第i个元素不存在
s=(LinkList)malloc(sizeof(Node));
//生成新结点
s->data=e;
s->next=p->next;
p->next=s;
return OK;
}
单链表的删除
p->next=p->next->next
算法思路
1.如果查找成功,将欲删除的结点p->next赋值给q ;
2.再执行p->next=q->next;
3.将结点q中的数据赋值给e;
4.释放结点q;
4.最后返回。
代码
Status GetElem (LinkList *L,int i,ElemType *e)
{
int j;
LinkList p,s;
p=*L;
j=1; //计数器
while(p->next&&j<i) //p不为空或者计数器j还没有等于i时,循环继续
{
p=p->next; //让p指向下一个结点
++j;
}
if(!p||j>i)
return ERROR;//第i个元素不存在
q=p->next;
p->next=q->next;
*e=q->data; //将q结点中数据给e
free(q); //回收此结点,释放内存
return OK;
}
双向链表
结点中有两个结点指针,分别指向前后两个结点,其它与单向链表完全一样。