目录
一.链表的定义
链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表
中的指针链接次序实现的 。
链表就和火车一样
![](https://i-blog.csdnimg.cn/blog_migrate/4030ad03c8381314b3e466e400f571b4.png)
每节火车就是链表中的结点,火车里只有一位
乘客,火车外有一个
连接器,用来连接下一节火车
而这里的乘客就是链表中的数据,连接器则是指向下一个链表节点的指针。
二.单链表的结构
我们之前说了链表由乘客和连接器组成,那么这两个东西该如何表示呢?
typedef int datatype; //typedef一下,如果换成其他类型更加方便
typedef struct SlistNode
{
datatype data;
struct SlistNode* next;
}SlistNode;
三.单链表的基本操作
先来看一下单链表有那些操作吧
SlistNode* BuyNewNode(datatype x); //申请一个结点
void SlistPushBack(SlistNode** phead, datatype x); //尾插
void SlistPrint(SlistNode* phead); //打印
void SlistPushFront(SlistNode** phead, datatype x); //头插
void SlistPopBack(SlistNode** phead); //尾删
void SlistPopFront(SlistNode** phead); //头删
SlistNode* SlistFind(SlistNode* phead, datatype x); //查找
void Freeposx(SlistNode** phead, SlistNode* pos); //释放pos地方的结点
void Insertposx(SlistNode** phead, SlistNode* pos,datatype x); //在pos地方插入一个结点
void InsertposAfter(SlistNode** phead, SlistNode* pos,datatype x); //在pos之后插入一个结点
void FreeposAfter(SlistNode** phead, SlistNode* pos); //在pos之后释放一个结点
void SlistDestroy(SlistNode**phead); //摧毁
1.申请一个结点
SlistNode* BuyNewNode(datatype x)
{
SlistNode* newnode = (SlistNode*)malloc(sizeof(SlistNode));
newnode->data = x;
newnode->next = NULL;
}
2.尾插
void SlistPushBack(SlistNode** phead, datatype x)
{
SlistNode* newnode = BuyNewNode(x);
SlistNode* tail = *phead;
//空链表的情况
if (*phead == NULL)
{
*phead = newnode;
}
//其余情况
else
{
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
}
这里要注意的是,我们写的是无头结点的单链表,所以当链表为空的时候,需要特殊处理。
3.打印
void SlistPrint(SlistNode* phead)
{
SlistNode* cur = phead;
while (cur)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
4.头插
void SlistPushFront(SlistNode** phead,datatype x)
{
SlistNode* newnode = BuyNewNode(x);
//无特殊情况
newnode->next = *phead;
*phead = newnode;
}
5.头删
void SlistPushFront(SlistNode** phead,datatype x)
{
SlistNode* newnode = BuyNewNode(x);
//无特殊情况
newnode->next = *phead;
*phead = newnode;
}
6.尾删
void SlistPopBack(SlistNode** phead)
{
SlistNode* tail = *phead;
SlistNode* prev = NULL;
//空表
assert(*phead);
//一个结点
if ((*phead)->next == NULL)
{
free(*phead);
*phead = NULL;
}
else
{
while (tail->next != NULL)
{
prev = tail;
tail = tail->next;
}
free(tail);
tail = NULL;
prev->next = NULL;
}
}
这里也需要注意,尾删的时候一个结点或是没有结点都是一种特殊情况,需要单独处理
7.查找
SlistNode* SlistFind(SlistNode* phead, datatype x)
{
SlistNode* cur = phead;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
8.释放pos地方的结点
void Freeposx(SlistNode** phead, SlistNode* pos)
{
assert(*phead);
SlistNode* prev = NULL;
//pos在头结点
if (pos==*phead)
{
SlistPopFront(phead);
}
//其他情况
else
{
SlistNode* prev = *phead;
//找到pos前面的结点
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
pos = NULL;
}
}
如果pos是头结点,则是头删。
9.在pos地方插入一个节点
void Insertposx(SlistNode** phead, SlistNode* pos, datatype x)
{
SlistNode* newnode = BuyNewNode(x);
SlistNode* prev = *phead;
//pos在头结点
if (pos == *phead)
{
SlistPopFront(phead, x);
}
//其他情况
else
{
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = newnode;
newnode->next = pos;
}
}
同上
10.在pos之后插入一个结点
void InsertposAfter(SlistNode** phead, SlistNode* pos, datatype x)
{
SlistNode* newnode = BuyNewNode(x);
SlistNode* next = pos->next;
pos->next = newnode;
newnode->next = next;
}
11.在pos之后释放一个结点
void FreeposAfter(SlistNode** phead, SlistNode* pos)
{
//不能是最后一个
assert(pos->next);
SlistNode* next = pos->next;
pos->next = next->next;
free(next);
next->next = NULL;
}
12.销毁
void SlistDestroy(SlistNode** phead)
{
SlistNode* cur = *phead;
while (cur)
{
SlistNode* next = cur->next;
free(cur);
cur = next;
}
*phead = NULL;
}