单链表(增删查改)

简介: 单链表(增删查改)

一、什么是单链表?


单链表是一种链式存取的数据结构,,链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。以“结点的序列”表示的线性表称作线性链表(单链表),单链表是链式存取的结构。简单来说单链表就是一个一个的节点链接起来的链式结构,每个节点里面存储着一个数据和与它链接的下一个节点的(指针)地址。(注意,每一个节点都是同一种结构体类型)


二、单链表的增删查改


2.1 结构体变量的声明


typedef int SLTDataType;
typedef struct SLTNode
{
  SLTDataType data;
  struct SLTNode* next;
}SLTNode;


2.2 申请新结点


SLTNode* BuySListNode(SLTDataType x)
{
  SLTNode* newNode = (SLTNode*)malloc(sizeof(SLTNode));
  if (newNode == NULL)
  {
    perror("malloc fail");
    return NULL;
  }
  else
  {
    newNode->data = x;
    newNode->next = NULL;
    return newNode;
  }
}


2.2 链表的头插


void SListPushFront(SLTNode** pphead, SLTDataType x)
{
  assert(pphead);
  SLTNode* newNode = BuySListNode(x);
  newNode->next = *pphead;
  *pphead = newNode;
}


2.3 链表的尾插


void SListPushBack(SLTNode** pphead, SLTDataType x)
{
  assert(pphead);
  SLTNode* newNode = BuySListNode(x);
  if (*pphead == NULL)
  {
    *pphead = newNode;
  }
  else
  {
    SLTNode* tail = *pphead;
    while (tail->next)
    {
      tail = tail->next;
    }
    tail->next = newNode;
  }
}


2.4 链表的头删


void SListPopFront(SLTNode** pphead)
{
  assert(pphead && *pphead);
  SLTNode* del = *pphead;
  *pphead = (*pphead)->next;
  free(del);
  del = NULL;
}


2.5 链表的尾删


void SListPopBack(SLTNode** pphead)
{
  assert(pphead);
  assert(*pphead);
  if ((*pphead)->next == NULL)
  {
    free(*pphead);
    *pphead = NULL;
  }
  else
  {
    SLTNode* tailPrev = NULL;
    SLTNode* tail = *pphead;
    while (tail->next)
    {
      tailPrev = tail;
      tail = tail->next;
    }
    tailPrev->next = NULL;
    free(tail);
    tail = NULL;
  }
}


2.6 链表的查找


SLTNode* SListFind(SLTNode* pphead, SLTDataType x)
{
  SLTNode* cur = pphead;
  while (cur)
  {
    if (cur->data == x)
    {
      return cur;
    }
    else
    {
      cur = cur->next;
    }
  }
  printf("找不到%d\n",x);
  return NULL;
}


2.7 链表的任意位置后面插入


void SListInsertAfter(SLTNode* pos, SLTDataType x)
{
  assert(pos);
  SLTNode* newNode = BuySListNode(x);
  SLTNode* posNext = pos->next;
  pos->next = newNode;
  newNode->next = posNext;
}


2.8 链表的任意位置后面删除


void SListEraseAfter(SLTNode* pos)
{
  assert(pos && pos->next);
  SLTNode* posNext = pos->next;
  pos->next = posNext->next;
  free(posNext);
  posNext = NULL;
}


2.9 链表的销毁


//建议传二级指针,因为销毁的话需要把这个指向链表的指针置空
//传一级指针无法把指向链表的指针置空
void SListDestroy(SLTNode** pphead)
{
  SLTNode* cur = *pphead;
  while (cur)
  {
    SLTNode* del = cur;
    cur = cur->next;
    free(del);
    del = NULL;
  }
  *pphead = NULL;
}


2.10 链表的打印


void SListPrint(SLTNode* phead)
{
  SLTNode* cur = phead;
  while (cur)
  {
    printf("%d->", cur->data);
    cur = cur->next;
  }
  printf("NULL\n");
}


三、代码汇总


3.1 SLish.h


#pragma once
//SList.h
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int SLTDataType;
typedef struct SLTNode
{
  SLTDataType data;
  struct SLTNode* next;
}SLTNode;
// 动态申请一个节点
extern SLTNode* BuySListNode(SLTDataType x);
// 单链表打印
extern void SListPrint(SLTNode* phead);
// 单链表尾插
extern void SListPushBack(SLTNode** pphead, SLTDataType x);
// 单链表的头插
extern void SListPushFront(SLTNode** pphead, SLTDataType x);
// 单链表的尾删
extern void SListPopBack(SLTNode** pphead);
// 单链表头删
extern void SListPopFront(SLTNode** pphead);
// 单链表查找
extern SLTNode* SListFind(SLTNode* pphead, SLTDataType x);
// 单链表在pos位置之后插入x
// 分析思考为什么不在pos位置之前插入?
extern void SListInsertAfter(SLTNode* pos, SLTDataType x);
// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置?
extern void SListEraseAfter(SLTNode* pos);
// 单链表的销毁
extern void SListDestroy(SLTNode** pphead);


3.2 SLish.c


#define _CRT_SECURE_NO_WARNINGS 1
//Slist.c
#include "SList.h"
SLTNode* BuySListNode(SLTDataType x)
{
  SLTNode* newNode = (SLTNode*)malloc(sizeof(SLTNode));
  if (newNode == NULL)
  {
    perror("malloc fail");
    return NULL;
  }
  else
  {
    newNode->data = x;
    newNode->next = NULL;
    return newNode;
  }
}
void SListPrint(SLTNode* phead)
{
  SLTNode* cur = phead;
  while (cur)
  {
    printf("%d->", cur->data);
    cur = cur->next;
  }
  printf("NULL\n");
}
void SListPushBack(SLTNode** pphead, SLTDataType x)
{
  assert(pphead);
  SLTNode* newNode = BuySListNode(x);
  if (*pphead == NULL)
  {
    *pphead = newNode;
  }
  else
  {
    SLTNode* tail = *pphead;
    while (tail->next)
    {
      tail = tail->next;
    }
    tail->next = newNode;
  }
}
void SListPushFront(SLTNode** pphead, SLTDataType x)
{
  assert(pphead);
  SLTNode* newNode = BuySListNode(x);
  newNode->next = *pphead;
  *pphead = newNode;
}
void SListPopBack(SLTNode** pphead)
{
  assert(pphead);
  assert(*pphead);
  if ((*pphead)->next == NULL)
  {
    free(*pphead);
    *pphead = NULL;
  }
  else
  {
    SLTNode* tailPrev = NULL;
    SLTNode* tail = *pphead;
    while (tail->next)
    {
      tailPrev = tail;
      tail = tail->next;
    }
    tailPrev->next = NULL;
    free(tail);
    tail = NULL;
  }
}
void SListPopFront(SLTNode** pphead)
{
  assert(pphead && *pphead);
  SLTNode* del = *pphead;
  *pphead = (*pphead)->next;
  free(del);
  del = NULL;
}
SLTNode* SListFind(SLTNode* pphead, SLTDataType x)
{
  SLTNode* cur = pphead;
  while (cur)
  {
    if (cur->data == x)
    {
      return cur;
    }
    else
    {
      cur = cur->next;
    }
  }
  printf("找不到%d\n",x);
  return NULL;
}
void SListInsertAfter(SLTNode* pos, SLTDataType x)
{
  assert(pos);
  SLTNode* newNode = BuySListNode(x);
  SLTNode* posNext = pos->next;
  pos->next = newNode;
  newNode->next = posNext;
}
void SListEraseAfter(SLTNode* pos)
{
  assert(pos && pos->next);
  SLTNode* posNext = pos->next;
  pos->next = posNext->next;
  free(posNext);
  posNext = NULL;
}
void SListDestroy(SLTNode** pphead)
{
  SLTNode* cur = *pphead;
  while (cur)
  {
    SLTNode* del = cur;
    cur = cur->next;
    free(del);
    del = NULL;
  }
  *pphead = NULL;
}


3.3 test.c


#define _CRT_SECURE_NO_WARNINGS 1
//test.c
#include "SList.h"
void test_SListPushBack(void)
{
  SLTNode* plist = NULL;
  SListPushBack(&plist, 1);
  SListPushBack(&plist, 2);
  SListPushBack(&plist, 3);
  SListPushBack(&plist, 4);
  SListPushBack(&plist, 5);
  SListPrint(plist);
  SLTNode* ret = SListFind(plist, 1);
  if (ret != NULL)
  {
    printf("找到了,地址为:%p\n", ret);
    SListInsertAfter(ret, 6);
    SListPrint(plist);
  }
  ret = SListFind(plist, 1);
  if (ret != NULL)
  {
    printf("找到了,地址为:%p\n", ret);
    SListInsertAfter(ret, 7);
    SListPrint(plist);
  }
  ret = SListFind(plist, 1);
  if (ret != NULL)
  {
    printf("找到了,地址为:%p\n", ret);
    SListInsertAfter(ret, 8);
    SListPrint(plist);
  }
  ret = SListFind(plist, 1);
  if (ret != NULL)
  {
    printf("找到了,地址为:%p\n", ret);
    SListInsertAfter(ret, 9);
    SListPrint(plist);
  }
  ret = SListFind(plist, 1);
  if (ret != NULL)
  {
    printf("找到了,地址为:%p\n", ret);
    SListInsertAfter(ret, 10);
    SListPrint(plist);
  }
  /*SLTNode* ret = SListFind(plist, 1);
  if (ret != NULL)
  {
    printf("找到了,地址为:%p\n", ret);
    SListEraseAfter(ret);
    SListPrint(plist);
  }
  ret = SListFind(plist, 1);
  if (ret != NULL)
  {
    printf("找到了,地址为:%p\n", ret);
    SListEraseAfter(ret);
    SListPrint(plist);
  }
  ret = SListFind(plist, 1);
  if (ret != NULL)
  {
    printf("找到了,地址为:%p\n", ret);
    SListEraseAfter(ret);
    SListPrint(plist);
  }
  ret = SListFind(plist, 1);
  if (ret != NULL)
  {
    printf("找到了,地址为:%p\n", ret);
    SListEraseAfter(ret);
    SListPrint(plist);
  }*/
  /*ret = SListFind(plist, 1);
  if (ret != NULL)
  {
    printf("找到了,地址为:%p\n", ret);
    SListEraseAfter(ret);
    SListPrint(plist);
  }*/
  //SListInsertAfter(ret, 8);
  /*SListPrint(plist);
  SListPopFront(&plist);
  SListPrint(plist);
  SListPopFront(&plist);
  SListPrint(plist); 
  SListPopFront(&plist);
  SListPrint(plist); 
  SListPopFront(&plist);
  SListPrint(plist); 
  SListPopFront(&plist);
  SListPrint(plist);*/
}
void test_SListPushFront(void)
{
  SLTNode* plist = NULL;
  SListPushFront(&plist, 1);
  SListPushFront(&plist, 2);
  SListPushFront(&plist, 3);
  SListPushFront(&plist, 4);
  SListPushFront(&plist, 5);
  SListPrint(plist);
  SListPopFront(&plist);
  SListPrint(plist);
  SListPopFront(&plist);
  SListPrint(plist);
  SListPopFront(&plist);
  SListPrint(plist);
  SListPopFront(&plist);
  SListPrint(plist);
  SListPopFront(&plist);
  SListPrint(plist);
  /*SListPopFront(&plist);
  SListPrint(plist);*/
  //SListDestroy(plist);
  //SListPrint(plist);
  /*SListPopBack(&plist);
  SListPrint(plist);
  SListPopBack(&plist);
  SListPrint(plist);
  SListPopBack(&plist);
  SListPrint(plist);
  SListPopBack(&plist);
  SListPrint(plist);
  SListPopBack(&plist);
  SListPrint(plist);*/
}
int main()
{
  //test_SListPushBack();
  test_SListPushFront();
  return 0;
}
相关文章
【链表】还不会用C++实现链表?一文教会你各种链表的实现
【链表】还不会用C++实现链表?一文教会你各种链表的实现
517 0
|
算法 调度 C++
【C/C++ 数据结构 线性表】C/C++中队列的原理与实现:从基础到循环队列
【C/C++ 数据结构 线性表】C/C++中队列的原理与实现:从基础到循环队列
419 0
|
11月前
|
算法 C语言
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
本文档介绍了如何编写两个子函数,分别求任意两个整数的最大公约数和最小公倍数。内容涵盖循环控制与跳转语句的使用、最大公约数的求法(包括辗转相除法和更相减损术),以及基于最大公约数求最小公倍数的方法。通过示例代码和测试说明,帮助读者理解和实现相关算法。最终提供了完整的通关代码及测试结果,确保编程任务的成功完成。
630 15
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
|
缓存 安全 Java
原子操作的实现原理
原子操作的实现原理
293 0
|
JSON 测试技术 持续交付
自动化测试与脚本编写:Python实践指南
自动化测试与脚本编写:Python实践指南
349 1
|
消息中间件 存储 网络协议
操作系统的心脏:深入理解进程间通信(IPC)机制
在现代计算机系统中,操作系统扮演着至关重要的角色,而进程间通信(IPC)作为操作系统的核心功能之一,极大地影响着系统的性能和稳定性。本文将通过浅显易懂的语言,详细探讨进程间通信的基本原理、主要类型及其实际应用,旨在为读者提供一个清晰且全面的理解和认识。 ##
841 1
|
存储 网络协议 机器人
04 ROS Client-Service-Server实例
本文通过实例讲解了ROS(机器人操作系统)中服务(Service)机制的工作原理,包括客户端请求服务的步骤、服务器提供服务的步骤,以及如何编写、编译和测试服务的客户端和服务器代码。
378 0
|
Linux Go
【Linux基础】 文件基本属性
Linux文件基本属性是指文件或目录在Linux系统中具有的一系列特性和信息。这些属性提供了关于文件或目录的详细信息,包括其类型、权限、大小、创建和修改时间等。本篇文章带你详细了解Linux属性概念,以及怎样更改文件属性。
281 0
【Linux基础】 文件基本属性
|
安全
多线程和异步编程:什么是线程安全?如何确保在多线程环境下的数据安全性?
多线程和异步编程:什么是线程安全?如何确保在多线程环境下的数据安全性?
1266 3
|
存储 安全 Linux
深入Linux进程内核:揭开进程工作原理的神秘面纱
深入Linux进程内核:揭开进程工作原理的神秘面纱
574 0

热门文章

最新文章