线性链表——单链表
线性链表
线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素。因此,为了表示每个数据元素x1与其后继元素x2之间的逻辑关系,对于数据x1来说,除了存储其本身的信息外,还需要存储一个指向其后继的信息。即需要一个存储数据的数据域,一个存储其后继的位置的指针域,它们俩构成一个节点,若干个节点组成一个链表。例如:
对于线性表来说,总得有个头,有个尾,链表也不例外。我们把链表中的第一个结点的存储位置叫做头指针,然后整个链表从头指针开始进行操作,之后的每一个结点,都是上一个结点的后继指针指向的位置。那么最后一个结点的后继指针指向那里呢?当然它后边是空的,那么就让它指向NULL。
有时,为了更加方便的对链表进行操作,会在单链表的第一个结点前附设一个结点,它被称为头结点。头节点的数据域可以不存储数据,也可以用来存储链表的长度信息,头结点的指针域存储指向第一个结点的指针。
一、头指针与头结点的异同
二、链表存储结构代码描述
1.构造结构体
typedef struct Node
{
ElemType data;
struct Node *next;
}Node;
typedef struct Node *LinkList;//定义LinkList
从这个结构定义中,我们知道,结点由存放数据元素的数据域存放后继结点地址的指针域组成。假设p是指向线性表的第i个元素的指针,则该结点a[i]的数据域我们可以用p->data来表示,p->data的值是一个数据元素,结点a[i]的指针域可以用p->next来表示,p->next的值也是一个指针。p->next指向的是第i+1个结点的位置,即指向a[i+1]的指针也就是说,p->data=a[i],那么p->next->data=a[i+1]。
2.单链表的读取
获得链表第i给数据的算法思路
1.生命一个结点p指向链表的第一个结点,初始化j从1开始;
2.当j
3.若到链表末p为空,则说明链表不足i个元素;
4.查找成功,返回p->data。
代码如下:
/*初始条件:线性表L已经存在*/
Status GetElem(LinkList L,int i,ElemType *e)
{
int j=1;
LinkList p//声明一个结点p
p=L->next;//让p指向链表的第一个结点
while(p && j
{
p=p->next;//p指向下一个结点
j++;
}
if( !p || j>i )
return 0;//第i个元素不存在
*e =p->data;//取第i给元素的数据
return 1;
}
3.单链表的插入与删除
先来看看单链表的插入。假设存储元素e的结点为s,要实现结点p,p->next和s间的逻辑关系的变化,只需将结点s插入到结点p和p->next之间即可。
事实上这种插入根本不用惊动其他结点,只需要让s->next和p->next的指针做一点改变即可
s->next=p->next;p->next=s;
这俩句代码的意思是让p的后继结点改成s的后继结点,再把结点s变成p的后继结点。
但这里要注意的是,一定要先把a[i+1]的地址给s的next,然后再把a[i]的后继改为s。若先把a[i]的后继改为s,就无法找到a[i+1]的地址了,也就丢失了后面的数据。
单链表第i个数据插入结点的算法思路:
1.声明一结点p指向链表的第一个结点,初始化j从1开始;
2.当j
3.若到链表末尾p为空,则说明第i个元素不存在;
4.否则查找成功,在系统中生成一个空结点s;
5.将数据元素e赋值给s->data;
6.单链表的插入标准预计s->next=p->next; p->next=s;
代码算法如下:
//操作结果: 在L的第i个位置之前插入新的数据元素e,L的长度+1
Status ListInsert(LinkList *L,int i,ElemType e)
{
int j;
LinkList p,s;
p=*L;
j=1;
while( p && j<1 )//寻找第i个结点
{
p=p->next;
++j;
}
if( !p || j>i )return 0;//第i个结点不存在
s=(LinkList)malloc (sizeof(Node));//生成新结点
s->data=e;
s->next=p->next;//将p的后继赋值给s的后继
p->next=s;//将s赋给p的后继
return 1;
}
再来看看单链表的删除
设存储元素a[i]的结点为q,要实现将结点q删除的操作,其实就是将它的前继结点的指针绕过q,指向q之后的结点。
单链表第i个数据删除节点的算法思路:
1.声明一个节点p指向链表,第一个结点,初始化j从1开始;
2.当j
3.若到链表末尾p为空,则说明第i个结点不存在;
4.否则查找成功,将要删除的结点p->next赋值给q;
5.单链表的删除标准语句p->next=q->next;
6.将q结点中的数据赋值给e;
7.释放q结点;
实现代码算法如下:
//操作结果:删除L的第i个数据元素,并用e返回其值
Status ListDelete(LinkList *L,int i,ElemType *e)
{
int j=1;
LinkList p,q;
p=*L;
while( p->next && j
{
p=p->next;
j++;
}
if ( !(p->next) || j>i ) return 0;//第i个元素不存在
q=p->next;
p->next=q->next;//将q的后继赋值给p的后继
*e=q->data;
free(q);//释放结点q
return 1;
}
总结
单链表的操作相对于顺序表来说,它的操作不会影响到其余的数据节点,操作更为方便快捷。
原文链接:https://blog.csdn.net/m0_46755575/article/details/108685094