关于单链表的基础部分增删查改的实现和一点理解,写在注释里~
SList.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//定义节点的结构
//数据 + 指向下一个节点的指针
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType data;//当前节点存储的数据
struct SListNode* next;//指向下一个节点的指针
}SLTNode;
//打印
void SLTPrint(SLTNode* phead);
//申请节点
SLTNode* SLTBuyNode(SLTDataType x);
//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x);
//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x);
//尾删
void SLTPopBack(SLTNode** pphead);
//头删
void SLTPopFront(SLTNode** pphead);
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos);
//销毁链表
void SListDesTroy(SLTNode** pphead);
SList.c
#include"SList.h"
//只要形参变了而实参没有变化,那么就什么传的是值,而不是地址
//data:节点存储的数据
//next:指向下一个节点的指针
//打印
void SLTPrint(SLTNode* phead)
{
//创建一个临时变量pcur将头节点的值赋予给pcur
//pcur指向当前节点的值
SLTNode* pcur = phead;
//判断pcur是否为空
while (pcur)
{
//打印指向当前节点存储的数据
printf("%d->", pcur->data);
//将pucr指向的下一个节点指针的地址赋予给pcur
pcur = pcur->next;
}
//当pcur为空时则打印NULL
printf("NULL\n");
}
//申请节点
SLTNode* SLTBuyNode(SLTDataType x)
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
if (newnode == NULL)
{
perror("malloc fail!");
exit(1);
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
//尾插
// 只要形参变了而实参没有变化,那么就什么传的是值,而不是地址
//要先找到尾节点,再把尾节点的next指针指向新节点(newnode)
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
//*pphead 就是指向第一个节点的指针
//申请一个新节点
SLTNode* newnode = SLTBuyNode(x);
//如果为空链表
if (*pphead == NULL)
{
*pphead = newnode;
}
else//非空链表
{
//找尾节点
//定义一个尾节点,链表刚开始头节点和尾节点在同一个位置
SLTNode* ptail = *pphead;//*pphead一级指针,指向第一个节点的指针
//判断当尾节点指针指向的下一个位置为NULL结束
//当ptail指针指向的下一个位置不为NULL时,ptail继续运行
while (ptail->next)
{
//把ptail指针指向的下一个位置的指针地址赋予ptail
ptail = ptail->next;
}
//当ptail指针指向的下一个位置为NULL时,ptail指向的就是尾结点
//将ptail的next指针指向新节点
ptail->next = newnode;
}
}
//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
//申请一个新节点
SLTNode* newnode = SLTBuyNode(x);
//*pphead一级指针,指向第一个节点的指针
//将新节点的next指针指向*pphead (头节点)
newnode->next = *pphead;
//然后再把新节点变成新的头节点*pphead
*pphead = newnode;
}
//尾删
void SLTPopBack(SLTNode** pphead)
{
//链表不能为空
assert(pphead && *pphead);
//如果链表只有一个节点
if ((*pphead)->next == NULL) // -> 优先级高于*
{
free(*pphead);
*pphead = NULL;
}
else//如果链表有多个节点
{
//定义一个函数prev(前一个)
//将prev和ptail都指向头节点 *pphead
SLTNode* prev = *pphead;
SLTNode* ptail = *pphead;
//判断ptail的next指针是否为空
while (ptail->next)
{
//将prev指向ptail的位置,ptail指向ptail的next指针的位置
prev = ptail;
ptail = ptail->next;
}
//如果ptail的next指针不为空,则把ptail free掉
free(ptail);
//将ptail和prev的next指针置为空
ptail = NULL;
prev->next = NULL;
}
}
//头删
void SLTPopFront(SLTNode** pphead)
{
//链表不能为空
assert(pphead && *pphead);
//定义一个next指针,将头节点的next指针指向第二个节点(next)
//用来保存第二个节点的位置
SLTNode* next = (*pphead)->next;
//释放头节点
free(*pphead);
//将第二个节点变成新的头节点
*pphead = next;
}
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
//定义一个指针pcur指向头节点
//这里不论pcur怎么变化都不会影响phead
SLTNode* pcur = phead;
//while循环遍历
while (pcur)
{
//判断当前节点存储的数据是否与要查找的值相同
if (pcur->data == x)
{
//如果是就返回pcur
return pcur;
}
//不是pcur就指向pcur的next指针继续走
pcur = pcur->next;
}
//如果结束循环还没有找到就返回NULL
return NULL;
}
//在指定位置之 前 插入数据 prev:上一个
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
//链表不能为空
assert(pphead && *pphead);
assert(pos);
//插入之前要先申请新节点
SLTNode* newnode = SLTBuyNode(x);
若pos == *pphead;说明是头插
if (pos == *pphead)
{
SLTPushFront(pphead, x);
}
else//不是头插
{
//先找到pos的前一个节点
//定义一个函数prev,指向头节点
SLTNode* prev = *pphead;
//如果prev的下一个指针指向的 不是 pos则进行循环
while (prev->next != pos)
{
//不是prev就指向prev的next指针继续走
prev = prev->data;
}
//找到之后
//prev->newnode->pos
//先将newnode的next指针指向pos,再把prev的next指针指向指向newnode
newnode->next = pos;
prev->next = newnode;
}
}
//在指定位置之 后 插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
assert(pos);
SLTNode* newnode = SLTBuyNode(x);
//pos -> newnode -> pos->next
//先将newnode的next指针指向pos的下一个节点(next),再把pos的next指针指向newnode
newnode->next = pos->next;
pos->next = newnode;
}
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
assert(pphead && *pphead);
assert(pos);
//pos是头结点
if (pos == *pphead)
{
//头删
SLTPopFront(pphead);
}
else//pos不是头结点
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
//prev pos pos->next
//要先把prev的下一个指针指向pos的下一个指针指向的位置再释放掉pos
// 防止找不到pos的下一个指针指向的位置
prev->next = pos->next;
free(pos);
pos = NULL;
}
}
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos)
{
assert(pos && pos->next);
//定义一个临时指针del,将pos的next指针存放到del中
SLTNode* del = pos->next;
//把pos的next指针指向del的next指针
//pos del del->next
pos->next = del->next;
free(del);
del = NULL;
}
//销毁链表
void SListDesTroy(SLTNode** pphead)
{
assert(pphead && *pphead);
SLTNode* pcur = *pphead;
while (pcur)
{
SLTNode* next = pcur->next;
free(pcur);
pcur = next;
}
//pcur
*pphead = NULL;
}
Test.c
#include"SList.h"
void SListTest01()
{
//链表是由一个一个的节点组成
//创建几个节点
SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));
node1->data = 1;
SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));
node2->data = 2;
SLTNode* node3 = (SLTNode*)malloc(sizeof(SLTNode));
node3->data = 3;
SLTNode* node4 = (SLTNode*)malloc(sizeof(SLTNode));
node4->data = 4;
//将四个节点连接起来
node1->next = node2;
node2->next = node3;
node3->next = node4;
node4->next = NULL;
//调用链表的打印
SLTNode* plist = node1;
SLTPrint(plist);
}
void SListTest02()
{
SLTNode* plist = NULL;
SLTPushBack(&plist, 1);
SLTPushBack(&plist, 2);
SLTPushBack(&plist, 3);
SLTPushBack(&plist, 4);
SLTPrint(plist); // 1->2->3->4->NULL
SListDesTroy(&plist);
SLTPrint(plist);
//测试查找
//SLTNode* find = SLTFind(plist, 1);
//SLTInsert(&plist, find, 11);
//SLTInsertAfter(find, 11);
//删除pos节点
//SLTErase(&plist, find);
//SLTEraseAfter(find);
//SLTPrint(plist);
//if (find == NULL)
//{
// printf("没有找到!\n");
//}
//else {
// printf("找到了!\n");
//}
//SLTPushBack(NULL, 5);
//
//测试头插
//SLTPushFront(&plist, 6);
//SLTPrint(plist);
//SLTPushFront(&plist, 7);
//SLTPrint(plist);
//SLTPushFront(&plist, 8);
//SLTPrint(plist);
//测试头删
//SLTPopFront(&plist);
//SLTPrint(plist);// 2->3->4->NULL
//SLTPopFront(&plist);
//SLTPrint(plist);
//SLTPopFront(&plist);
//SLTPrint(plist);
//SLTPopFront(&plist);
//SLTPrint(plist);
//SLTPopFront(&plist);
//SLTPrint(plist);
}
int main()
{
//SListTest01();
SListTest02();
return 0;
}
一点浅解,感谢观看~