一. 单链表定义(single linked list)
概念: 链表是一种物理存储结构 上非连续、非顺序 的存储结构,但链表在逻辑上 是连续的,顺序的,而数据元素的逻辑顺序是通过链表中的指针连接次序实现的。
所谓单链表就是:单向链表 ,我们将链表中的每个元素称之为结点/节点 ,单链表中的每个节点是单向的 ,也就是说,我们无法直接获得某一结点的前面的第一个结点,即:前驱结点。
二. 结构
链表是由一个个结点组成的
单链表是一种常见的数据结构,用于存储和操作一系列的数据。它由节点组成,每个节点包含数据和指向下一个节点的指针。
三. 链表的实现
1> 定义结点
typedef int SLTDateType;
typedef struct SListNode
{
SLTDateType Date;
SListNode* next;
}SListNode;
2> 链表功能
//创建一个结点
SLTNode* BuyListNode(SLTDateType x);
//销毁单链表
void SLTDestory(SLTNode** pphead);
//单链表头插
void SLTPushFront(SLTNode** pphead, SLTDateType x);
//单链表尾插
void SLTPushBack(SLTNode** pphead, SLTDateType x);
//单链表头删
void SLTPopFront(SLTNode** pphead);
//单链表尾删
void SLTPopBack(SLTNode** pphead);
//单链表结点查找
SLTNode* SLTNodeFind(SLTNode* phead, SLTDateType x);
//单链表结点删除(删除pos位置的结点)
void SLTErase(SLTNode** pphead, SLTNode* pos);
//单链表结点插入(在pos之前插入)
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x);
// 单链表结点插入(在pos之后插入)
void SLTInsertBack(SLTNode** pphead, SLTNode* pos, SLTDateType x);
// 单链表结点修改
void SLTModify(SLTNode* phead, SLTNode* pos, SLTDateType x);
//打印单链表
void PrintSLT(SLTNode * phead);
3> 链表功能的实现
略
#include"SLT.h"
//建立一个新的结点
//这是链表的缺点:经常需要使用malloc为newnode开辟空间
SLTNode* BuyListNode(SLTDateType x)
{
//为什么要用malloc,是因为,如果在BuyListNode函数中SLTNode newnode,出了这个函数,newnode就被销毁了,
//用malloc开辟空间,只要我们不主动释放这个空间,这个空间的数据一直存在,
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
//static SLTNode newnode;
if (newnode == NULL)
{
perror("malloc:");
exit(0);
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
//头插
void SLTPushFront(SLTNode** pphead, SLTDateType x)
{
assert(pphead);//phead可能为NULL,但是pphead指向phead,不可能为空
SLTNode* newnode = BuyListNode(x);
//这里可不是newnode->next = (*pphead)->next;
newnode->next = *pphead;
*pphead = newnode;
}
//尾插
//尾插特别容易出错,当链表中没有数据,即phead=NULL时,尾插就相当于头插了,此时需要改变phead的值
void SLTPushBack(SLTNode** pphead, SLTDateType x)
{
assert(pphead);
SLTNode* newnode = BuyListNode(x);
//1、空
//2、非空
if (*pphead == NULL)
{
*pphead = newnode;
//newnode->next = NULL;这一步是不需要的,newnode在建立的时候就默认newnode->next=NULL;
}
else
{
SLTNode* cur = *pphead;
//这是单向链表的缺点,需要去找尾
while (cur->next != NULL)
{
cur = cur->next;
}
cur->next = newnode;
}
}
//头删
void SLTPopFront(SLTNode** pphead)
{
assert(pphead);
//温柔的检查
if (*pphead == NULL)
return;
//暴力的检查
assert(*pphead);
SLTNode* head = *pphead;
*pphead = (*pphead)->next;
free(head);
head = NULL;
}
//尾删
void SLTPopBack(SLTNode** pphead)
{
assert(pphead);
assert(*pphead);
//1、一个结点
//2、两个结点
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
SLTNode* cur = *pphead;
while (cur->next->next)
{
cur = cur->next;
}
free(cur->next);
cur->next = NULL;
}
}
//打印单向链表
void PrintSLT(SLTNode* phead)
{
SLTNode* cur = phead;
while (cur != NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL");
printf("\n");
}
//单链表查找某个结点
SLTNode* SLTNodeFind(SLTNode* phead, SLTDateType x)
{
SLTNode* find = phead;
//别忘记分析找不到结点的情况
while (find)
{
if (find->data == x)
{
return find;
}
find = find->next;
}
return NULL;
}
//删除pos位置的结点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
assert(pphead);
assert(pos);
if (pos == *pphead)
{
SLTPopFront(pphead);
}
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
//如果prev->next已经为空了,说明链表已经查完了,还没有查到pos
//证明pos传入有误
assert(prev->next);
}
prev->next = pos->next;
free(pos);
//pos = NULL;这个没必要,改变不了pos
}
}
//单链表结点前插
//一般插入结点都是在pos之前插入,但单链表在实现前插是比较困难的
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{
assert(pphead);
//头插
if (pos == *pphead)
{
SLTPushFront(pphead, x);
}
//非头插
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
assert(prev->next);
}
SLTNode* newnode = BuyListNode(x);
prev->next = newnode;
newnode->next = pos;
}
}
//单链表结点后插
void SLTInsertBack(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{
SLTNode* cur = *pphead;
while (cur != pos)
{
cur = cur->next;
//防止pos传错了
assert(cur);
}
SLTNode* newnode = BuyListNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
// 单链表结点修改
void SLTModify(SLTNode* phead, SLTNode* pos, SLTDateType x)
{
SLTNode* cur = phead;
while (cur != pos)
{
cur = cur->next;
assert(cur);
}
pos->data = x;
}
//销毁链表
void SLTDestory(SLTNode** pphead)
{
assert(pphead);
SLTNode* cur = *pphead;
//比cur->next!=NULL更好一些
while (cur)
{
SLTNode* next = cur->next;
free(cur);
cur = next;
}
*pphead = NULL;
}
更加详细的请看原文【数据结构】------单链表超详细介绍(独家介绍,小白必看!!!)-CSDN博客
❤️❤️❤️