系列文章参考资料为《大话数据结构》,源码为个人私有,未经允许不得转载 技术交流群或资料添加微信号:CoderAllen,回复关键字即可
线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素,可以使连续的,也可以不连续,也就意味这些元素可以存在内存未被占用的任意位置
链式结构中,除了要存储元素信息外(数据域),还要存储它的后继元素的存储地址(指针域),这两部分信息组成的数据元素称为结点(Node)
链表的每个结点只包含一个指针域叫做单链表,特点是每个结点的指针域将线性表的数据元素按其逻辑次序链接在一起
其中第一个结点位置叫做头指针,线性链表的最后一个结点指针为空(NULL)
为了方便对链表的操作,会在单链表的第一个结点前附设一个结点,称为头结点,头结点可以不存储任何信息,也可以存储线性表的长度等信息,头结点的指针域指向第一个结点的指针
更加方便的存储示意图表示单链表
单链表可以用结构指针描述
typedef struct Node
{
ElemType data;
struct Node *next;
}Node;
typedef struct Node *LinkList; /* 定义LinkList */
单链表的读取
获得链表第i个数据的算法思路
代码实现:(主要思想就是“工作指针后移”)
/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:用e返回L中第i个数据元素的值 */
Status GetElem(LinkList L,int i,ElemType *e)
{
int j;
LinkList p; /* 声明一结点p */
p = L->next; /* 让p指向链表L的第一个结点 */
j = 1; /* j为计数器 */
while (p && jnext; /* 让p指向下一个结点 */
++j;
}
if ( !p || j>i )
return ERROR; /* 第i个元素不存在 */
*e = p->data; /* 取第i个元素的数据 */
return OK;
}
上述步骤比单链表麻烦很多,不过有利有弊,下边看下插入和删除
单链表的插入单链表的插入不需要惊动其他结点,只需要s->next=p->next , p->next=s,原理如下图
结果就是下边这样
插入的算法思想:
代码实现:
/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L), */
/* 操作结果:在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 next;
++j;
}
if (!p || j > i)
return ERROR; /* 第i个元素不存在 */
s = (LinkList)malloc(sizeof(Node)); /* 生成新结点(C语言标准函数) */
s->data = e;
s->next = p->next; /* 将p的后继结点赋值给s的后继 */
p->next = s; /* 将s赋值给p的后继 */
return OK;
}
单链表的删除
同插入类似,删除就是烧过删除的结点
算法思路
代码实现
/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
Status ListDelete(LinkList *L,int i,ElemType *e)
{
int j;
LinkList p,q;
p = *L;
j = 1;
while (p->next && j next;
++j;
}
if (!(p->next) || j > i)
return ERROR; /* 第i个元素不存在 */
q = p->next;
p->next = q->next; /* 将q的后继赋值给p的后继 */
*e = q->data; /* 将q结点中的数据给e */
free(q); /* 让系统回收此结点,释放内存 */
return OK;
}
结合插入和删除操作,对于频繁的操作,单链表的效率优势明显
--------------------------------------------------------END----------------------------------------------------------- 电子书及源码点击下载