概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。
注:以上概念以及图片均来自比特科技。
**SList.h**
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
typedef int SLTDataType;
typedef struct SListNote
{
SLTDataType data;
struct SListNote* next;
}SLTNote;
//打印
void SListPrint(SLTNote* phead);
//尾插
void SListPushBack(SLTNote** pphead, SLTDataType x);
//尾删
void SListPopBack(SLTNote** pphead);
//头插
void SListPushFront(SLTNote** pphead, SLTDataType x);
//头删
void SListPopFront(SLTNote** pphead);
//查找
SLTNote* SListFind(SLTNote* phead, SLTDataType x);
//在pos位置之前插入
void SListInsert(SLTNote** pphead, SLTNote* pos, SLTDataType x);
//删除pos位置的值
void SListErase(SLTNote** pphead, SLTNote* pos);
// 单链表插入pos位置之后的值
void SListInsertAfter(SLTNote* pos, SLTDataType x);
// 单链表删除pos位置之后的值
void SListEraseAfter(SLTNote* pos);
**SList.c**
#include"SList.h"
//打印
void SListPrint(const SLTNote* phead)
{
SLTNote* cur = phead;
while (cur != NULL)
{
printf("%d -> ", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
SLTNote* BuySListNote(SLTDataType x)
{
//创建结点
SLTNote* newnode = (SLTNote*)malloc(sizeof(SLTNote));
assert(newnode);
newnode->data = x;
newnode->next = NULL;
return newnode;
}
//尾插
void SListPushBack(SLTNote** pphead, SLTDataType x)
{
assert(pphead);//注:所有二级指针都必须要检查,因为就算链表为NULL,二级指针也不能为NULL;
SLTNote* newnode = BuySListNote(x);
if (*pphead == NULL)
{
//没有结点
*pphead = newnode;
}
else
{
//找尾结点
SLTNote* tail = *pphead;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
//为什么*pphead 改变用二级指针,而tail改变next不需要二级指针?
//PushBack改变实参plist,实参直接传给形参pphead,pphead改变不会影响实参
//因为在这里形参pphead是实参plist的一份临时拷贝,如果想要改变实参,这里需要传址
//而这里tail之所以不用二级指针,是因为这里改变的是结构体tail所指向的next,而不是改变tail这个指针变量
//综述,pphead是想改变一级指针,所以使用二级指针
//tail是想改变结构体
}
}
//头插
void SListPushFront(SLTNote** pphead, SLTDataType x)
{
assert(pphead);
SLTNote* newnode = BuySListNote(x);
newnode->next = *pphead;
*pphead = newnode;
}
//尾删
void SListPopBack(SLTNote** pphead)
{
assert(*pphead);
//只有一个结点
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
//多个结点 方法①
SLTNote* tail = *pphead;
SLTNote* tailPrev = NULL;//记录尾结点前一结点
while (tail->next != NULL)
{
tailPrev = tail;
tail = tail->next;
}
free(tail);//释放掉尾结点
tailPrev->next = NULL;//尾结点的前一结点next指向设置为NULL
//方法②
//SLTNote* tail = *pphead;
//while (tail->next->next != NULL)
//{
// tail = tail->next;
//}
//free(tail->next);
//tail->next = NULL;
}
}
//头删
void SListPopFront(SLTNote** pphead)
{
assert(*pphead);
assert(pphead);
SLTNote* second = (*pphead)->next; //保留下一个结点位置
free(*pphead);//释放头部结点
*pphead = second;//将下一个结点地址传给plist
}
//查找 /修改
SLTNote* SListFind(SLTNote* phead, SLTDataType x)
{
assert(phead);
SLTNote* cur = phead;
while (cur)
{
if (cur->data == x)
return cur;
cur = cur->next;
}
return NULL;
}
//在pos位置之前插入
void SListInsert(SLTNote** pphead, SLTNote* pos, SLTDataType x)
{
assert(pos);
assert(pphead);
//头插
if (pos == *pphead)
{
SListPushFront(pphead, x);
}
else
{
SLTNote* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
SLTNote* newnode = BuySListNote(x);//创建结点
prev->next = newnode;
newnode->next = pos;
}
//为什么需要传一个二级的头指针?
// ①:因为插入的时候有可能pos是第一个结点,这里可以直接调用头插
// ②:这里是为了方便找到pos前一个结点的位置
//为什么pos传的不是下标,而是结点的指针?
//因为一般SListInsert是与查找SListFind函数联合使用,日常使用场景是在某个val值前面插入x。
}
//删除pos位置的值
void SListErase(SLTNote** pphead, SLTNote* pos)
{
assert(pphead);
assert(pos);
//头删
if (*pphead == NULL)
{
SListPopFront(pphead);
}
else
{
SLTNote* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
pos = NULL;
}
}
// 单链表插入pos位置之后的值
void SListInsertAfter(SLTNote* pos, SLTDataType x)
{
assert(pos);
SLTNote* newnode = BuySListNote(x);
//方法① :注意顺序
//newnode->next = pos->next;
//pos->next = newnode->next;
//不在乎顺序 方法②
SLTNote* scond = pos->next;
pos->next = newnode->next;
newnode->next = scond;
}
// 单链表删除pos位置之后的值
void SListEraseAfter(SLTNote* pos)
{
assert(pos);
//尾结点
if (pos->next == NULL)
{
return;
}
SLTNote* del = pos->next;
pos->next = del->next;
free(del);
del = NULL;
}
**test.c**
#include"SList.h"
void TestSList1()
{
//struct SListNote*
SLTNote* n1 = (SLTNote*)malloc(sizeof(SLTNote));
assert(n1);
SLTNote* n2 = (SLTNote*)malloc(sizeof(SLTNote));
assert(n2);
SLTNote* n3 = (SLTNote*)malloc(sizeof(SLTNote));
assert(n3);
SLTNote* n4 = (SLTNote*)malloc(sizeof(SLTNote));
assert(n4);
n1->data = 1;
n2->data = 2;
n3->data = 3;
n4->data = 4;
n1->next = n2;
n2->next = n3;
n3->next = n4;
n4->next = NULL;
//SListPrint(n1);
SLTNote* plist = n1;
SListPrint(n1);
SListPushBack(&plist, 5);
SListPushBack(&plist, 6);
SListPushBack(&plist, 7);
SListPushBack(&plist, 8);
SListPrint(plist);
}
void TestSList2()//测试尾插
{
SLTNote* plist = NULL;
SListPushBack(&plist, 1); //改变变量,传变量的地址,解引用改变
SListPushBack(&plist, 2); //该变指针变量,传指针变量的地址,解引用改变 (二级指针)
SListPushBack(&plist, 3);
SListPushBack(&plist, 4);
SListPrint(plist);
}
void TestSList3()//测试头插
{
SLTNote* plist = NULL;
SListPushBack(&plist, 1);
SListPushBack(&plist, 2);
SListPushBack(&plist, 3);
SListPushBack(&plist, 4);
SListPrint(plist);
SListPushFront(&plist, 0);
SListPrint(plist);
SListPopFront(&plist);
SListPrint(plist);
}
void TestSList4()//测试尾删
{
SLTNote* plist = NULL;
SListPushBack(&plist, 1);
SListPushBack(&plist, 2);
SListPushBack(&plist, 3);
SListPushBack(&plist, 4);
SListPrint(plist);
SListPopBack(&plist);
SListPrint(plist);
SListPopBack(&plist);
SListPrint(plist);
SListPopBack(&plist);
SListPrint(plist);
SListPopBack(&plist);
SListPrint(plist);
//SListPopBack(&plist);
//SListPrint(plist);
}
void TestSList5()//测试
{
SLTNote* plist = NULL;
SListPushBack(&plist, 1);
SListPushBack(&plist, 2);
SListPushBack(&plist, 3);
SListPushBack(&plist, 4);
SListPrint(plist);
SLTNote* ret = SListFind(plist, 3);
if (ret)
{
printf("找到了\n");
ret->data = 30;
}
SListPrint(plist);
SLTNote* pos = SListFind(plist, 4);
if (pos)
{
SListInsert(&plist, pos, 40);
}
SListPrint(plist);
}
void TestSList6()//测试
{
SLTNote* plist = NULL;
SListPushBack(&plist, 1);
SListPushBack(&plist, 2);
SListPushBack(&plist, 3);
SListPushBack(&plist, 4);
SListPrint(plist);
SLTNote* pos = SListFind(plist, 4);
if (pos)
{
SListErase(&plist, pos);
}
SListPrint(plist);
}
int main()
{
TestSList6();
return 0;
}