前言
本文重点讲述单链表的增删查改,有喜欢的老铁留下你们的三连!!
链表基本概念
概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。
每一个节点就相当于一个火车的车厢,指针就相当于火车之间的挂钩,通过指针将这些原本不连续的空间联系起来
链表的创建
typedef int SLTDateType;
typedef struct SListNode
{
SLTDateType data;
struct SListNode* next;
}SLTNode;
链表所需的功能函数
void SListPrint(SLTNode* phead);
SLTNode* BuySListNode(SLTDateType x);
void SListPushBack(SLTNode** phead, SLTDateType x);
void SListPushFront(SLTNode** phead, SLTDateType x);
void SListPopBack(SLTNode** phead);
void SListPopFront(SLTNode** phead);
SLTNode* SListFind(SLTNode* phead, SLTDateType x);
void SListInsertAfter(SLTNode* pos, SLTDateType x);
void SListInsertBefor(SLTNode*phead,SLTNode* pos, SLTDateType x);
void SListEraseAfter(SLTNode* pos);
void SListEraseBefor(SLTNode** phead,SLTNode* pos);
void SListDestory(SLTNode* phead);
函数的具体实现
1.打印链表
这个很简单,就是遍历而已,重点就是phead = phead->next,这是将phead赋值成下一个结点,有同学会问,这里传的指针那你不改变了头结点的位置了嘛,那不就都混了嘛??(重点)
我们首先得明白结点是用的指针表示的也就是一级指针,那我们要想改变一级指针指向的地址,那我们得用二级指针来控制,不然不会改变一级指针指向的结点!!!
void SListPrint(SLTNode* phead)
{
assert(phead);
while (phead!= NULL)
{
printf("%d->", phead->data);
phead = phead->next;
}
printf("NULL\n");
}
2.动态申请一个节点
这个由于后续函数都要申请新节点,所以我们直接封装一个新函数
SLTNode* BuySListNode(SLTDateType x)
{
SLTNode* newnext = (SLTNode*)malloc(sizeof(SLTNode));
assert(newnext);
newnext->data = x;
newnext->next = NULL;
return newnext;
}
3.尾插
void SListPushBack(SLTNode** phead, SLTDateType x)
{
SLTNode* newnext = BuySListNode(x);
SLTNode* cur = *phead;
if (*phead == NULL)
{
*phead = newnext;
}
else
{
while (cur->next != NULL)
{
cur = cur->next;
}
cur->next = newnext;
}
}
4.头插
void SListPushFront(SLTNode** phead, SLTDateType x)
{
SLTNode* newnext = BuySListNode(x);
newnext->next = *phead;
*phead = newnext;
}
5.尾删
void SListPopBack(SLTNode** phead)
{
assert(*phead);
if (( * phead)->next == NULL)
{
free(*phead);
*phead = NULL;
}
else
{
SLTNode* tail = *phead;
while (tail->next->next != NULL)
{
tail = tail->next;
}
free(tail->next);
tail->next=NULL;
}
}
6.头删
void SListPopFront(SLTNode** phead)
{
assert(*phead);
SLTNode* cur = (*phead)->next;
free(*phead);
*phead = cur;
}
7.单链表查找
SLTNode* SListFind(SLTNode* phead, SLTDateType x)
{
SLTNode* cur = phead;
while (cur)
{
if (cur->data == x)
return cur;
else
cur = cur->next;
}
return NULL;
}
8.单链表在pos位置之后插入x
void SListInsertAfter(SLTNode* pos, SLTDateType x)
{
assert(pos);
SLTNode* next = pos->next;
SLTNode *newnext=BuySListNode(x);
pos->next = newnext;
newnext->next = next;
}
9.单链表在pos位置之后插入x
void SListInsertBefor(SLTNode**phead,SLTNode* pos, SLTDateType x)
{
assert(pos);
if (pos == *phead)
{
SListPushFront(phead,x);
}
else
{
SLTNode* newnext = BuySListNode(x);
SLTNode* posprev = *phead;
while (posprev->next != pos)
{
posprev = posprev->next;
}
posprev->next = newnext;
newnext->next = pos;
}
}
10.单链表删除pos后面的值
void SListEraseAfter(SLTNode* pos)
{
assert(pos);
SLTNode* next = pos->next;
if (pos->next != NULL)
{
pos->next = pos->next->next;
free(next);
}
}
11.单链表删除pos前面的值
void SListEraseBefor(SLTNode** phead, SLTNode* pos)
{
assert(pos&&(pos!=*phead));
if ((*phead)->next == pos)
{
SListPopFront(phead);
}
else
{
SLTNode* tail = *phead;
while (tail->next->next != pos)
{
tail = tail->next;
}
SLTNode* next = tail->next;
tail->next = pos;
free(next);
}
}
12.单链表的销毁
void SListDestory(SLTNode* phead)
{
SLTNode* next = phead->next;
while (phead != NULL)
{
free(phead);
phead = next;
if(next!=NULL)
next = next->next;
}
}
函数总汇
#define _CRT_SECURE_NO_WARNINGS
#include "SList.h"
void SListPrint(SLTNode* phead)
{
assert(phead);
while (phead!= NULL)
{
printf("%d->", phead->data);
phead = phead->next;
}
printf("NULL\n");
}
SLTNode* BuySListNode(SLTDateType x)
{
SLTNode* newnext = (SLTNode*)malloc(sizeof(SLTNode));
assert(newnext);
newnext->data = x;
newnext->next = NULL;
return newnext;
}
void SListPushBack(SLTNode** phead, SLTDateType x)
{
SLTNode* newnext = BuySListNode(x);
SLTNode* cur = *phead;
if (*phead == NULL)
{
*phead = newnext;
}
else
{
while (cur->next != NULL)
{
cur = cur->next;
}
cur->next = newnext;
}
}
void SListPushFront(SLTNode** phead, SLTDateType x)
{
SLTNode* newnext = BuySListNode(x);
newnext->next = *phead;
*phead = newnext;
}
void SListPopBack(SLTNode** phead)
{
assert(*phead);
if (( * phead)->next == NULL)
{
free(*phead);
*phead = NULL;
}
else
{
SLTNode* tail = *phead;
while (tail->next->next != NULL)
{
tail = tail->next;
}
free(tail->next);
tail->next=NULL;
}
}
void SListPopFront(SLTNode** phead)
{
assert(*phead);
SLTNode* cur = (*phead)->next;
free(*phead);
*phead = cur;
}
SLTNode* SListFind(SLTNode* phead, SLTDateType x)
{
SLTNode* cur = phead;
while (cur)
{
if (cur->data == x)
return cur;
else
cur = cur->next;
}
return NULL;
}
void SListInsertAfter(SLTNode* pos, SLTDateType x)
{
assert(pos);
SLTNode* next = pos->next;
SLTNode *newnext=BuySListNode(x);
pos->next = newnext;
newnext->next = next;
}
void SListInsertBefor(SLTNode**phead,SLTNode* pos, SLTDateType x)
{
assert(pos);
if (pos == *phead)
{
SListPushFront(phead,x);
}
else
{
SLTNode* newnext = BuySListNode(x);
SLTNode* posprev = *phead;
while (posprev->next != pos)
{
posprev = posprev->next;
}
posprev->next = newnext;
newnext->next = pos;
}
}
void SListEraseAfter(SLTNode* pos)
{
assert(pos);
SLTNode* next = pos->next;
if (pos->next != NULL)
{
pos->next = pos->next->next;
free(next);
}
}
void SListEraseBefor(SLTNode** phead, SLTNode* pos)
{
assert(pos&&(pos!=*phead));
if ((*phead)->next == pos)
{
SListPopFront(phead);
}
else
{
SLTNode* tail = *phead;
while (tail->next->next != pos)
{
tail = tail->next;
}
SLTNode* next = tail->next;
tail->next = pos;
free(next);
}
}
void SListDestory(SLTNode* phead)
{
SLTNode* next = phead->next;
while (phead != NULL)
{
free(phead);
phead = next;
if(next!=NULL)
next = next->next;
}
}
ps:学习链表要学会多画图,因为这东西对于初学者来说比较抽象,还有一个点就是为什么总是要创建中间变量来存储结点,这是因为你讲前面一个结点和后面一个结点联系起来了,如果没有用中间变量提前存储的话,会导致你调用不了这个结点
看图: 这里想要删除2,是不是要先将2这个结点保存下来呀,不保存就找不到了,然后再free掉它!! 还有同学问 我不能先free掉2然后让1指向3吗,这里因为2被free了所以1不能通过2找到3了 ,所以还是不行,就相当于下图一样中间没联系了
本文结束,有疑问的老铁欢迎留言!!
|