SList.h
#pragma once
//单链表
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType data;
struct SListNode* next;
}SLTNode;
//打印结果
void SLTPrint(SLTNode* phead);
//头插
void SLPushFront(SLTNode** pphead, SLTDataType x);
//尾插
void SLPushTail(SLTNode** pphead, SLTDataType x);
//头删
void SLPopFront(SLTNode** pphead);
//尾删
void SLPopTail(SLTNode** pphead);
// pphead 指向 plist 存放的是 plist 的地址 , *pphead 找到的是 plist
//查找
SLTNode* SLFind(SLTNode* plist, SLTDataType x);
//不修改,传一级指针,修改时,传二级
//在任意位置(pos)之前插入
void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//在 pos 后插入
void SListInsertAfter(SLTNode* pos, SLTDataType x);
//删除 pos 位置的值
void SListErase(SLTNode** pphead, SLTNode* pos);
//删除 pos 位置后面的值
void SLEraseAfter(SLTNode* pos);
// 单链表的销毁
void SListDestroy(SLTNode** pphead);
SList.c
#include"SList.h"
#define _CRT_SECURE_NO_WARNINGS
//打印结果
void SLTPrint(SLTNode* phead)
{
//assert(phead);//空链表 --- 可以打印
SLTNode* cur = phead;
while (cur != NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
//插入数据时,在堆区开辟空间
SLTNode* Plug_space(SLTDataType x)
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
if (newnode == NULL)
{
perror("malloc fail");
return NULL;
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
//头插
void SLPushFront(SLTNode** pphead,SLTDataType x)
{
assert(pphead);
//pphead 是 plist 的地址
//当 链表为空时,即 plist 为空, *pphead 为空 ,pphead 不为空
//若 pphead 为空,在 @1 处,会出现对空指针的解引用
//assert(*pphead);//不需要,空链表可以插入数据
/*SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
if(newnode == NULL)
{
perror("malloc fail");
return;
}
newnode->data = x;
newnode->next = NULL;*/
SLTNode* newnode = Plug_space(x);
newnode->next = *pphead;
*pphead = newnode; //@1
}
//尾插
void SLPushTail(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
//assert(*pphead);
//插入 --- 开辟一块新的空间,在头插过程中也需要开辟一块新的空间,可以将其分装为函数
SLTNode* newnode = Plug_space(x);
if (*pphead == NULL)
{
*pphead = newnode;//链表中为空,尾插的数据为 newnode
//要改变的是节点的指针,节点指针的地址(二级指针)
}
else
{
//找尾节点指针
SLTNode* tail = *pphead;
while (tail->next != NULL)
{
tail = tail->next;
}
//尾节点,链接新节点
tail->next = newnode;//要改变的是节点(next成员),节点指针
}
}
//头删
void SLPopFront(SLTNode** pphead)
{
assert(pphead);
//pphead 是 plist 的地址
//当 链表为空时,即 plist 为空, *pphead 为空 ,pphead 不为空
//若 pphead 为空,在 @2 处,会出现对空指针的解引用
//断言,链表是否为空
assert(*pphead);//链表为空,不能头删
/*
//链表中有一个或多个
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;//@2
}
else
{
SLTNode* del = *pphead;
*pphead = del->next;//跳过第一个节点
//*pphead = (*pphead)->next;
//此处无法识别优先级问题
free(del);
}
*/
//可以替代上述链表中有一个多个的问题
SLTNode* del = *pphead;
//*pphead = del->next;//跳过第一个节点
*pphead = (*pphead)->next;
//此处无法识别优先级问题
free(del);
}
//尾删 1
//void SLPopTail(SLTNode** pphead)
//{
// //判断链表是否为空,若链表为空,则无法进行尾删,进行断言
// assert(*pphead);//*pphead 指向 plist
//
// //分为链表中有一个/多个
// if ((*pphead)->next == NULL)
// {
// free(*pphead);
// *pphead = NULL;
// }
// //多个
// else
// {
// SLTNode* del = *pphead;
// //寻找倒数第二个,其 next 的 next 为 NULL,将 倒数第二个的 next 置为 NULL
// //找尾
// while(del->next->next)
// {
// del = del->next;
// }
// free(del->next);
// del->next = NULL;
// }
//}
//尾删 2
void SLPopTail(SLTNode** pphead)
{
assert(pphead);
//pphead 是 plist 的地址
//当 链表为空时,即 plist 为空, *pphead 为空 ,pphead 不为空
//若 pphead 为空,在 @3 处,会出现对空指针的解引用
//判断链表是否为空,若链表为空,则无法进行尾删,进行断言
assert(*pphead);//*pphead 指向 plist
//分为链表中有一个/多个
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;//@3
}
//多个
else
{
SLTNode* del = *pphead;
SLTNode* prve = NULL;
while (del->next)
{
prve = del;
del = del->next;
}
free(del);
prve->next = NULL;
}
}
//查找
SLTNode* SLFind(SLTNode* phead, SLTDataType x)
{
//assert(phead);//此处不需要断言,空链表可以查找
SLTNode* cur = phead;
while (cur)//若此处为 cur->next ,会导致最后一个节点进不去,需要在循环结束后手动添加
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;//没找到
}
//在任意位置(pos)之前插入
void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
assert(pphead);
assert(pos);
//若 pos 位于起始位置
if (*pphead == pos)
{
//等价于头插
SLPushFront(pphead, x);
}
// pos 位于其他位置,可以寻找其前一个位置
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
//当 prev-> next 为 pos 时,开辟一个新的空间,进行指针指向的转换,将其连接在一起
SLTNode* newnode = Plug_space(x);
prev->next = newnode;
newnode->next = pos;
}
}
//在 pos 后插入
void SListInsertAfter(SLTNode* pos, SLTDataType x)
{
assert(pos);
SLTNode* newnode = Plug_space(x);
newnode->next = pos->next;
pos->next = newnode;
/*
pos->next = newnode;
newnode->next = pos->next;// newnode->next = newnode
*/
}
//删除 pos 位置的值
void SListErase(SLTNode** pphead, SLTNode* pos)
{
assert(pphead);
assert(pos);
if (*pphead == pos)
{
//头删
SLPopFront(pphead);
}
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
//当 prev->next == pos
prev->next = pos->next;
free(pos);
}
}
//删除 pos 位置后面的值
void SLEraseAfter(SLTNode* pos)
{
assert(pos);
assert(pos->next);//最后一个
/*pos->next = pos->next->next;
free(pos->next);*/
//此处 free(pos->next) 就无法找到 pos->next->next
SLTNode* next = pos->next;
pos->next = next->next;
free(next);// 不影响 pos->next 和 pos->next->next
}
// 单链表的销毁
void SListDestroy(SLTNode** pphead)
{
//一个节点一个节点的释放
assert(pphead);
SLTNode* cur = *pphead;
while (cur)
{
SLTNode* next = cur->next;
free(cur);
cur = next;
}
*pphead = NULL;
}
//传一级指针,需要在tast.c中将 plist = NULL;
tast.c
#include"SList.h"
#define _CRT_SECURE_NO_WARNINGS
//头插
void TestSList1()
{
SLTNode* plist = NULL;
SLPushFront(&plist, 1);
SLPushFront(&plist, 2);
SLPushFront(&plist, 3);
SLPushFront(&plist, 4);
SLPushFront(&plist, 5);
SLPushFront(&plist, 6);
SLTPrint(plist);
}
//尾插
void TestSList2()
{
SLTNode* plist = NULL;
SLPushFront(&plist, 6);
SLPushTail(&plist, 1);
SLPushTail(&plist, 2);
SLPushTail(&plist, 3);
SLPushTail(&plist, 4);
SLPushTail(&plist, 5);
SLTPrint(plist);
}
//尾删
void TestSList3()
{
//头插
SLTNode* plist = NULL;
SLPushFront(&plist, 1);
SLPushFront(&plist, 2);
SLPushFront(&plist, 3);
SLPushFront(&plist, 4);
SLPushFront(&plist, 5);
SLPushFront(&plist, 6);
SLTPrint(plist);
SLPopTail(&plist);
SLTPrint(plist);
}
//查找
void TestSList4()
{
//头插
SLTNode* plist = NULL;
SLPushFront(&plist, 1);
SLPushFront(&plist, 2);
SLPushFront(&plist, 3);
SLPushFront(&plist, 4);
SLPushFront(&plist, 5);
SLPushFront(&plist, 6);
SLTPrint(plist);
//查找
SLTNode* pos = SLFind(plist, 3);
SLTPrint(plist);
//修改
if (pos)
pos->data = 10;
SLTPrint(plist);
}
//修改 pos 前 / 后 的值
void TestSList5()
{
//头插
SLTNode* plist = NULL;
SLPushFront(&plist, 1);
SLPushFront(&plist, 2);
SLPushFront(&plist, 3);
SLPushFront(&plist, 4);
SLPushFront(&plist, 5);
SLPushFront(&plist, 6);
SLTPrint(plist);
//查找
SLTNode* pos = SLFind(plist, 3);
SLTPrint(plist);
//修改 pos 前的值
if (pos)
{
SLInsert(&plist, pos, 10);
}
SLTPrint(plist);
pos = SLFind(plist, 2);
//修改 pos 后的值
if (pos)
{
SListInsertAfter(pos, 20);
}
SLTPrint(plist);
}
//删除 pos 位置的值
void TestSList6()
{
SLTNode* plist = NULL;
SLPushTail(&plist, 1);
SLPushTail(&plist, 2);
SLPushTail(&plist, 3);
SLPushTail(&plist, 4);
SLPushTail(&plist, 5);
SLTPrint(plist);
//查找
SLTNode* pos = SLFind(plist, 3);
SLTPrint(plist);
pos = SLFind(plist, 4);
//删除
if (pos)
{
SListErase(&plist, pos);
}
SLTPrint(plist);
}
//删除 pos 后位置的值
void TestSList7()
{
SLTNode* plist = NULL;
SLPushTail(&plist, 1);
SLPushTail(&plist, 2);
SLPushTail(&plist, 3);
SLPushTail(&plist, 4);
SLPushTail(&plist, 5);
SLTPrint(plist);
//查找
SLTNode* pos = SLFind(plist, 3);
SLTPrint(plist);
pos = SLFind(plist, 1);
//删除
if (pos)
{
SLEraseAfter(pos);
}
SLTPrint(plist);
}
int main()
{
//TestSList1();
//TestSList2();
//TestSList3();
//TestSList4();
/*TestSList5();*/
TestSList6();
/*TestSList7();*/
return 0;
}