【数据结构】单链表---C语言版(全网最最最最细!小白必必必必看!!!有图有真相!)(二)

简介: 【数据结构】单链表---C语言版(全网最最最最细!小白必必必必看!!!有图有真相!)(二)

⭕接口7:头删(SLTPopFront)

🚨要注意头删有三种情况:1.没有结点(空链表)、2.一个结点、3.多个结点

链表为空不能头删,所以要进行assert断言

🥰请看代码与注释👇

//头删
void SLTPopFront(SLTNode** pphead)
{
  //没有结点(空链表)
  assert(*pphead);  //链表为空,不能头删
  assert(pphead);
  //一个结点
  if ((*pphead)->next == NULL)
  {
    free(*pphead);
    *pphead = NULL;
  }
  //多个结点
  else
  {
    SLTNode* cur = *pphead;
    *pphead = cur->next;
    free(cur);
  }
}

可以有更简洁高效的写法👇

🥰请看代码与注释👇

//头删
void SLTPopFront(SLTNode** pphead)
{
  //没有结点(空链表)
  assert(*pphead);
  assert(pphead);
  //一个结点
  //多个结点
  SLTNode* cur = *pphead;
  *pphead = (*pphead)->next;
  free(cur);
}

⭕接口8:尾删(SLTPopBack)

🚨要注意尾删同样有三种情况:1.没有结点(空链表)、2.一个结点、3.多个结点

链表为空不能尾删,所以要进行assert断言

🥰请看代码与注释👇

//尾删
void SLTPopBack(SLTNode** pphead)
{
  //没有结点(空链表)
  assert(*pphead);
  assert(pphead);
  //一个结点
  if ((*pphead)->next == NULL)
  {
    free(*pphead);
    *pphead = NULL;
  }
  //多个结点
  else
  {
    SLTNode* tail = *pphead;
    //找尾
    while (tail->next->next)
    {
      tail = tail->next;
    }
    free(tail->next);
    tail->next = NULL;
  }
}

⭕接口9:查找(SLTFind)

通过遍历进行查找,通常与修改结合联系使用

🥰请看代码与注释👇

//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
  assert(phead);
  SLTNode* cur = phead;
  while (cur)
  {
    if (cur->data == x)
    {
      return cur;
    }
    else
    {
      cur = cur->next;
    }
  }
  return NULL;
}

⭕接口10:修改(SLTModify)

🥰请看代码与注释👇

//修改
void SLTModify(SLTNode* phead, SLTNode* pos, SLTDataType x)
{
  assert(phead);
  assert(pos);
  pos->data = x;
}

⭕接口11:在pos位置之前插入数据(SLTInsert)

🥰请看代码与注释👇

//在pos位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
  assert(pphead);
  assert(pos);  //防止给的位置为 空
  if (*pphead == pos)
  {
    SLTPushFront(pphead, x);
  }
  else
  {
    SLTNode* prev = *pphead;
    while (prev->next != pos)
    {
      prev = prev->next;
    }
    SLTNode* newnode = BuyLTNode(x);
    prev->next = newnode;
    newnode->next = pos;
  }
}

⭕接口12:在pos位置之后插入数据(SLTInsertAfter)

🥰请看代码与注释👇

//在pos位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
  assert(pos);  //防止给的位置为 空
  SLTNode* newnode = BuyLTNode(x);
  newnode->next = pos->next;
  pos->next = newnode;
}

⭕接口13:删除pos位置的值(SLTErase)

🥰请看代码与注释👇

//删除pos位置的值
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
  assert(pphead);
  assert(pos);  //防止给的位置为 空
  if (*pphead == pos)
  {
    SLTPopFront(pphead);
  }
  else
  {
    SLTNode* prev = *pphead;
    while (prev->next != pos)
    {
      prev = prev->next;
    }
    prev->next = pos->next;
    free(pos);
  }
}

⭕接口14:删除pos位置之后的值(SLTEraseAfter)

🥰请看代码与注释👇

//删除pos位置之后的值
void SLTEraseAfter(SLTNode* pos)
{
  assert(pos);
  assert(pos->next);
  SLTNode* next = pos->next;
  pos->next = next->next;
  free(next);
}

🐸四、完整代码

🥝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);
//释放
void SLTDestroy(SLTNode** pphead);
//创建新结点
SLTNode* BuyLTNode(SLTDataType x);
//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x);
//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x);
//头删
void SLTPopFront(SLTNode** pphead);
//尾删
void SLTPopBack(SLTNode** pphead);
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
//修改
void SLTModify(SLTNode* phead, SLTNode* pos, SLTDataType x);
//在pos位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//在pos位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
//删除pos位置的值
void SLTErase(SLTNode** pphead, SLTNode* pos);
//删除pos位置之后的值
void SLTEraseAfter(SLTNode* pos);

🥝SList.c

#include"SList.h"
//打印
void SLTPrint(SLTNode* phead)
{
  SLTNode* cur = phead;
  while (cur != NULL)
  {
    printf("%d-> ", cur->data);
    cur = cur->next;
  }
  printf("NULL\n");
}
//释放
void SLTDestroy(SLTNode** pphead)
{
  assert(pphead);
  SLTNode* cur = *pphead;
  while (cur)
  {
    SLTNode* next = cur->next;
    free(cur);
    cur = next;
  }
  *pphead = NULL;
}
//创建新结点
SLTNode* BuyLTNode(SLTDataType x)
{
  SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
  if (newnode == NULL)
  {
    perror("mallic fail");
    return;
  }
  newnode->data = x;
  newnode->next = NULL;
  return newnode;
}
//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{ 
  assert(pphead);   //链表为空,pphead也不为空,因为他是头指针plist的地址
                    // *pphead 不能断言,链表为空,也需要能插入
  SLTNode* newnode = BuyLTNode(x);
  newnode->next = *pphead;
  *pphead = newnode;
}
//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
  assert(pphead);
  SLTNode* newnode = BuyLTNode(x);
  //1.空链表
  //2.非空链表
  if (*pphead == NULL)
  {
    *pphead = newnode;    //改变的结构体的指针plist(用结构体指针的地址)
  }
  else
  {
    SLTNode* tail = *pphead;
    while (tail->next != NULL)
    {
      tail = tail->next;
    }
    tail->next = newnode;    //改变的结构体尾结点
  }
}
//头删
void SLTPopFront(SLTNode** pphead)
{
  //没有结点(空链表)
  assert(*pphead);  //链表为空,不能头删
  assert(pphead);
  //一个结点
  if ((*pphead)->next == NULL)
  {
    free(*pphead);
    *pphead = NULL;
  }
  //多个结点
  else
  {
    SLTNode* cur = *pphead;
    *pphead = cur->next;
    free(cur);
  }
}
//头删
//void SLTPopFront(SLTNode** pphead)
//{
//  //没有结点(空链表)
//  assert(*pphead);
//  assert(pphead);
//
//  //一个结点
//  //多个结点
//  SLTNode* cur = *pphead;
//  *pphead = (*pphead)->next;
//  free(cur);
//}
//尾删
void SLTPopBack(SLTNode** pphead)
{
  //没有结点(空链表)
  assert(*pphead);
  assert(pphead);
  //一个结点
  if ((*pphead)->next == NULL)
  {
    free(*pphead);
    *pphead = NULL;
  }
  //多个结点
  else
  {
    SLTNode* tail = *pphead;
    //找尾
    while (tail->next->next)
    {
      tail = tail->next;
    }
    free(tail->next);
    tail->next = NULL;
  }
}
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
  assert(phead);
  SLTNode* cur = phead;
  while (cur)
  {
    if (cur->data == x)
    {
      return cur;
    }
    else
    {
      cur = cur->next;
    }
  }
  return NULL;
}
//修改
void SLTModify(SLTNode* phead, SLTNode* pos, SLTDataType x)
{
  assert(phead);
  assert(pos);
  pos->data = x;
}
//在pos位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
  assert(pphead);
  assert(pos);  //防止给的位置为 空
  if (*pphead == pos)
  {
    SLTPushFront(pphead, x);
  }
  else
  {
    SLTNode* prev = *pphead;
    while (prev->next != pos)
    {
      prev = prev->next;
    }
    SLTNode* newnode = BuyLTNode(x);
    prev->next = newnode;
    newnode->next = pos;
  }
}
//在pos位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
  assert(pos);  //防止给的位置为 空
  SLTNode* newnode = BuyLTNode(x);
  newnode->next = pos->next;
  pos->next = newnode;
}
//删除pos位置的值
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
  assert(pphead);
  assert(pos);  //防止给的位置为 空
  if (*pphead == pos)
  {
    SLTPopFront(pphead);
  }
  else
  {
    SLTNode* prev = *pphead;
    while (prev->next != pos)
    {
      prev = prev->next;
    }
    prev->next = pos->next;
    free(pos);
  }
}
//删除pos位置之后的值
void SLTEraseAfter(SLTNode* pos)
{
  assert(pos);
  assert(pos->next);
  SLTNode* next = pos->next;
  pos->next = next->next;
  free(next);
}

🥝Test.c

#include"SList.h"
//头插测试
void TestSList01()
{
  SLTNode* plist = NULL;
  SLTPushFront(&plist, 1);
  SLTPushFront(&plist, 2);
  SLTPushFront(&plist, 3);
  SLTPushFront(&plist, 4);
  SLTPrint(plist);
  SLTDestroy(&plist);
}
//尾插测试
void TestSList02()
{
  SLTNode* plist = NULL;
  SLTPushFront(&plist, 1);
  SLTPushFront(&plist, 2);
  SLTPushFront(&plist, 3);
  SLTPushFront(&plist, 4);
  SLTPushBack(&plist, 5);
  SLTPushBack(&plist, 6);
  SLTPushBack(&plist, 7);
  SLTPrint(plist);
  SLTDestroy(&plist);
}
//头删测试
void TestSList03()
{
  SLTNode* plist = NULL;
  SLTPushFront(&plist, 1);
  SLTPushFront(&plist, 2);
  SLTPushFront(&plist, 3);
  SLTPushFront(&plist, 4);
  SLTPrint(plist);
  SLTPopFront(&plist);
  SLTPrint(plist);
  SLTPopFront(&plist);
  SLTPrint(plist);
  SLTPopFront(&plist);
  SLTPrint(plist);
  SLTPopFront(&plist);
  SLTPrint(plist);
  SLTDestroy(&plist);
}
//尾删测试
void TestSList04()
{
  SLTNode* plist = NULL;
  SLTPushFront(&plist, 1);
  SLTPushFront(&plist, 2);
  SLTPushFront(&plist, 3);
  SLTPushFront(&plist, 4);
  SLTPrint(plist);
  SLTPopBack(&plist);
  SLTPrint(plist);
  SLTPopBack(&plist);
  SLTPrint(plist);
  SLTPopBack(&plist);
  SLTPrint(plist);
  SLTPopBack(&plist);
  SLTPrint(plist);
  SLTDestroy(&plist);
}
//查找修改测试
void TestSList05()
{
  SLTNode* plist = NULL;
  SLTPushFront(&plist, 1);
  SLTPushFront(&plist, 2);
  SLTPushFront(&plist, 3);
  SLTPushFront(&plist, 4);
  SLTPrint(plist);
  SLTNode* pos = SLTFind(plist, 3);
  if (pos)
  {
    SLTModify(plist, pos, 8);
  }
  SLTPrint(plist);
  SLTDestroy(&plist);
}
//在pos位置之前插入数据测试
void TestSList06()
{
  SLTNode* plist = NULL;
  SLTPushFront(&plist, 1);
  SLTPushFront(&plist, 2);
  SLTPushFront(&plist, 3);
  SLTPushFront(&plist, 4);
  SLTPrint(plist);
  SLTNode* pos = SLTFind(plist, 3);
  if (pos)
  {
    SLTInsert(&plist, pos, 30);
  }
  SLTPrint(plist);
  SLTDestroy(&plist);
}
//在pos位置之后插入数据测试
void TestSList07()
{
  SLTNode* plist = NULL;
  SLTPushFront(&plist, 1);
  SLTPushFront(&plist, 2);
  SLTPushFront(&plist, 3);
  SLTPushFront(&plist, 4);
  SLTPrint(plist);
  SLTNode* pos = SLTFind(plist, 2);
  if (pos)
  {
    SLTInsertAfter(pos, 20);
  }
  SLTPrint(plist);
  SLTDestroy(&plist);
}
//删除pos位置的值测试
void TestSList08()
{
  SLTNode* plist = NULL;
  SLTPushFront(&plist, 1);
  SLTPushFront(&plist, 2);
  SLTPushFront(&plist, 3);
  SLTPushFront(&plist, 4);
  SLTPrint(plist);
  SLTNode* pos = SLTFind(plist, 3);
  if (pos)
  {
    SLTErase(&plist,pos);
  }
  SLTPrint(plist);
  SLTDestroy(&plist);
}
//删除pos位置之后的值测试
void TestSList09()
{
  SLTNode* plist = NULL;
  SLTPushFront(&plist, 1);
  SLTPushFront(&plist, 2);
  SLTPushFront(&plist, 3);
  SLTPushFront(&plist, 4);
  SLTPrint(plist);
  SLTNode* pos = SLTFind(plist, 2);
  if (pos)
  {
    SLTEraseAfter(pos);
  }
  SLTPrint(plist);
  SLTDestroy(&plist);
}
int main()
{
  //TestSList01();
  //TestSList02();
  //TestSList03();
  //TestSList04();
  //TestSList05();
  //TestSList06();
  //TestSList07();
  //TestSList08();
  //TestSList09();
  return 0;
}

😍这期内容些许复杂,需要慢慢理解消化哦!

总结🥰
以上就是 【数据结构】单链表—C语言版 的全部内容啦🥳🥳🥳🥳
本文章所在【数据结构与算法】专栏,感兴趣的烙铁可以订阅本专栏哦🥳🥳🥳
前途很远,也很暗,但是不要怕,不怕的人面前才有路。💕💕💕
小的会继续学习,继续努力带来更好的作品😊😊😊
创作写文不易,还多请各位大佬uu们多多支持哦🥰🥰🥰

目录
相关文章
|
2天前
|
C++
数据结构(循环单链表
数据结构(循环单链表
10 2
|
2天前
|
C++
数据结构(单链表
数据结构(单链表
9 0
|
2天前
|
存储
[数据结构]单链表(从0->1)
[数据结构]单链表(从0->1)
|
2天前
|
搜索推荐 C语言
【C语言/数据结构】排序(归并排序|计数排序|排序算法复杂度)
【C语言/数据结构】排序(归并排序|计数排序|排序算法复杂度)
11 0
|
2天前
|
C语言
【C语言/数据结构】排序(快速排序及多种优化|递归及非递归版本)
【C语言/数据结构】排序(快速排序及多种优化|递归及非递归版本)
11 0
|
2天前
|
C语言
【C语言/数据结构】排序(选择排序,推排序,冒泡排序)
【C语言/数据结构】排序(选择排序,推排序,冒泡排序)
13 0
|
2天前
|
C语言
【C语言/数据结构】排序(直接插入排序|希尔排序)
【C语言/数据结构】排序(直接插入排序|希尔排序)
15 4
|
2天前
|
C语言
【C语言/数据结构】二叉树(层序遍历|判断完全二叉树|性质)
【C语言/数据结构】二叉树(层序遍历|判断完全二叉树|性质)
280 52
|
2天前
|
机器学习/深度学习 算法 测试技术
【单调栈】3113. 边界元素是最大值的子数组数目
【单调栈】3113. 边界元素是最大值的子数组数目
|
2天前
|
存储 NoSQL C语言
数据结构——顺序栈与链式栈的实现-2
数据结构——顺序栈与链式栈的实现
数据结构——顺序栈与链式栈的实现-2