数据结构——C语言实现链表

article/2025/9/14 12:39:16

目录

一. 链表的概念

二. 单链表的增删查改

1.单链表的定义

2.单链表的头插与头删

3.单链表的尾插与尾删

4.单链表的中间插入删除

5.单链表的查找

三. 带头循环双向链表的增删查改

1.带头循环双向链表的定义

2.带头循环双向链表的头插与头删

3.带头循环双向链表的尾插与尾删

4.带头循环双向链表的中间插入删除

5.带头循环双向链表的查找


一. 链表的概念

概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表
中的指针链接次序实现的 。

在这里介绍链表中的两种结构

在这里插入图片描述

在这里插入图片描述

无头单向非循环列表:结构简单,一般不会单独用来存放数据。实际中更多是作为其他数据结构的子结构,比如说哈希桶等等。
带头双向循环链表:结构最复杂,一般单独存储数据。实际中经常使用的链表数据结构,都是带头双向循环链表。这个结构虽然复杂,但是使用代码实现后会发现这个结构会带来很多优势,实现反而简单了。

二. 单链表的增删查改

1.单链表的定义

在C语言中我们一般创建一个结构体来作为链表的结点

typedef int SLDataType;
typedef struct SListNode
{SLDataType data;struct SListNode* next;
}SListNode;

 创建初始化一个节点:

void SListInitNode(SListNode** plist, SLDataType x)
{assert(plist);*plist = (SListNode*)malloc(sizeof(SListNode));assert(*plist);(*plist)->data = x;(*plist)->next = NULL;
}

2.单链表的头插与头删

1.头插

void SListPushFront(SListNode** plist, SLDataType x)
{assert(plist);SListNode* ptr = *plist;SListInitNode(plist, x);(*plist)->next = ptr;
}

2.头删

void SListPopFront(SListNode** plist)
{assert(*plist);assert(plist);SListNode* ptr = (*plist)->next;free(*plist);*plist = ptr;
}

3.单链表的尾插与尾删

1.尾插

void SListPushBack(SListNode** plist, SLDataType x)
{assert(plist);if (*plist == NULL){SListInitNode(plist, x);}else{SListNode* ptr = *plist;while (ptr->next){ptr = ptr->next;}SListInitNode(&(ptr->next), x);}
}

2.尾删

void SListPopBack(SListNode** plist)
{assert(plist);assert(*plist);if ((*plist)->next == NULL){free(*plist);*plist = NULL;}else{SListNode* ptr = *plist;while (ptr->next->next){ptr = ptr->next;}free(ptr->next);ptr->next = NULL;}
}

4.单链表的中间插入删除

1.在pos位置之后插入

为什么不在pos位置之前插入?

在pos位置之前插入需要传单链表的二级指针,

1.用来解决pos指向单链表的头部出现的头插情况

2.用来寻找插入位置的前一个位置,以改变其指向

void SListInsertAfter(SListNode* pos, SLDataType x)
{assert(pos);SListNode* ptr = NULL;ptr = (SListNode*)malloc(sizeof(SListNode));assert(ptr);ptr->data = x;ptr->next = pos->next;pos->next = ptr;
}

2.在pos位置之后删除

为什么不删除pos位置?
删除pos位置同样需要传入单链表的二级指针,

1.用来解决pos指向单链表的头部出现的单链表指针指向的改变

2.用来寻找pos位置的前一个位置,以改变其指向

void SListEraseAfter(SListNode* pos)
{assert(pos);assert(pos->next);SListNode* ptr = pos->next;pos->next = pos->next->next;free(ptr);ptr = NULL;
}

5.单链表的查找

SListNode* SListFind(SListNode* plist, SLDataType x)
{assert(plist);while (plist){if (plist->data == x)return plist;plist = plist->next;}return NULL;
}

三. 带头循环双向链表的增删查改

1.带头循环双向链表的定义

在C语言中我们一般创建一个结构体来作为链表的结点

typedef int LDataType;
typedef struct ListNode
{LDataType data;struct ListNode* next;struct ListNode* prev;
}ListNode;

创建一个节点:

ListNode* BuyListNode()
{ListNode* tmp = (ListNode*)malloc(sizeof(ListNode));if (tmp == NULL){perror("malloc");}return tmp;
}

2.带头循环双向链表的头插与头删

1.头插

void ListPushfront(ListNode* phead, LDataType x)
{assert(phead);ListNode* newnode = BuyListNode();ListNode* tail = phead->next;phead->next = newnode;newnode->next = tail;newnode->prev = phead;tail->prev = newnode;newnode->data = x;//ListInsert(phead->next, x);
}

2.头删

void ListPopFront(ListNode* phead)
{assert(phead);ListNode* tail = phead->next;tail->next->prev = phead;phead->next = tail->next;free(tail);//ListErase(phead->next);
}

3.带头循环双向链表的尾插与尾删

1.尾插

void ListPushBack(ListNode* phead, LDataType x)
{ListNode* plist = BuyListNode();ListNode* tail = phead->prev;tail->next = plist;plist->prev = tail;plist->next = phead;phead->prev = plist;plist->data = x;//ListInsert(phead, x);
}

2.尾删

void ListPopBack(ListNode* phead)
{assert(phead);ListNode* tail = phead->prev;tail->prev->next = phead;phead->prev = tail->prev;free(tail);//ListErase(phead->prev);
}

4.带头循环双向链表的中间插入删除

1.插入

void ListInsert(ListNode* pos, LDataType x)
{assert(pos);ListNode* newnode = BuyListNode();pos->prev->next = newnode;newnode->prev = pos->prev;newnode->next = pos;pos->prev = newnode;newnode->data = x;
}

2.删除

void ListErase(ListNode* pos)
{assert(pos);pos->prev->next = pos->next;pos->next->prev = pos->prev;free(pos);
}

5.带头循环双向链表的查找

ListNode* ListFind(ListNode* phead, LDataType x)
{assert(phead);ListNode* cur = phead->next;while (phead != cur){if (cur->data == x)return cur;cur = cur->next;}return NULL;
}


http://chatgpt.dhexx.cn/article/akp9HUap.shtml

相关文章

C语言之链表详解

目录 一、链表定义 二、链表分类 三、链表操作 四、单向链表 1.链表定义 2.插入操作 3.删除操作 4.修改操作 5.查找操作 五、双向链表 1.链表定义 2.插入操作 3.删除操作 4.修改操作 5.查找操作 一、链表定义 链表是一种基本的数据结构,它由一系列节…

C语言 链表创建及操作

C语言 链表创建及操作 第一部分构建链表,定义结构体,分别用头插法、尾插法实现,这里封装了打印函数:printf();做练习方便后续使用;对链表进行查找,并将查找到的值构建一个新的链表;链表的转置&…

Netty权威指南 读书笔记

文档太大,PDF格式的存档已上传到百度网盘: 链接: https://pan.baidu.com/s/1QnUDWujGOXXCq5iWQBIRJg 提取码: q46s

Netty权威指南(第2版) pdf百度网盘下载

欢迎大家关注我的公众号【老周聊架构】,Java后端主流技术栈的原理、源码分析、架构以及各种互联网高并发、高性能、高可用的解决方案。 链接: https://pan.baidu.com/s/1DfxG9qKU2fshi6ha1a8NkA 提取码: bmt4

Netty权威指南带目录完整版.pdf

2019独角兽企业重金招聘Python工程师标准>>> Netty权威指南带目录完整版.pdf 转载于:https://my.oschina.net/xiaojianyu/blog/3011828

Netty权威指南总结(三)

五、Netty实战技巧: (一) 多线程编程实践: 1. Netty中使用多线程的技巧: 创建两个NioEventLoopGroup,用于逻辑隔离NIO Acceptor和NIO IO线程。 尽量不要在ChannelHandler中启动用户线程(解码后用于将POJO消息派发到后端…

Netty权威指南(四)TCP粘包/拆包问题

TCP粘包/拆包问题解决之道 上一章一、介绍1.1 TCP粘包/拆包问题说明1.2 TCP粘包/拆包发生的原因1.3 粘包问题的解决策略 二、未考虑TCP粘包导致的功能异常案例2.1 TimeServerHandler的改造2.2 TimeClientHandler的改造2.3 运行 三、利用LineBasedFrameDecoder解决TCP粘包问题3.…

《Netty权威指南》

《Netty权威指南》 基本信息 作者: 李林锋 出版社:电子工业出版社 ISBN:9787121233432 上架时间:2014-5-29 出版日期:2014 年6月 开本:16开 页码:524 版次:1-1 所属分类&#xff…

Netty权威指南~第一章Java的I/O演进之路

本章内容如下: 5种网络I/O模型的介绍I/O多路复用的介绍 1、I/O基础入门 在Java1.4之前,Java对I/O的支持不完善,开发人员在开发高性能I/O的程序时,会面临以下问题: 没有数据缓冲区,I/O性能存在问题没有C…

Netty权威指南(第2版)

网站 更多书籍点击进入>> CiCi岛 下载 电子版仅供预览及学习交流使用,下载后请24小时内删除,支持正版,喜欢的请购买正版书籍 电子书下载(皮皮云盘-点击“普通下载”)购买正版 封页 编辑推荐 1、Hadoop、Storm、Spark、Facebook、…

Netty权威指南——WebSocket协议开发

一、简介 由于HTTP协议的开销,导致他们不适于用于低延迟应用,为了解决这些问题,WebSocket将网络套接字引入到了客户端和服务端,浏览器和服务器之间可以通过套接字建立持久的连接,双方随时可以互发数据给对方&#xff…

netty权威指南 微云_《Netty权威指南》(二)NIO 入门

2.1 BIO 采用 BIO 通信模型的服务器,通常由一个独立的 Acceptor 线程负责监听客户端的连接,它接收到客户端连接请求之后为每个客户端创建一个新的线程进行处理,处理完成后,通过输出流返回应答给客户端,线程销毁。 grap…

netty 权威指南~第11章——WebSoket协议开发

本章主要学习内容如下: 1、WebSocket入门 2、Netty WebSocket协议开发 第节一:WebSocket入门 WebSocket是HTML5开始提供的一种浏览器与服务器进行全双通信的网络技术,WebSocket通信协议与2011年被IEIF定位标准RFC6455,WebsSock…

Netty权威指南 第2版

https://www.cnblogs.com/plxz/p/9910493.html 第一章  Java的I/O演进之路 1.I/O基础入门 1.Linux网络I/O模型简介 1.阻塞I/O模型:最常用的I/O模型,缺省情况下, 所有文件操作都是阻塞的 2.非阻塞I/O模型:recvform从应用层到内…

Netty权威指南总结(一)

一、为什么选择Netty: API使用简单,开发门槛低,屏蔽了NIO通信的底层细节。 功能强大,预制了很多种编解码功能,支持主流协议。 定制能力强,可以通过ChannelHandler对通信框架进行灵活地拓展。 性能高、成熟、…

Netty权威指南

Chapter1.java I/O演进之路 1.1I/O基础入门 在java 1.4之前,java程序员在开发高性能I/O程序的时候,会面临的问题主要有: 1.没有数据缓冲区,I/O性能存在问题 2.没有c或者c中的Channel概念,只有输入和输出流 3.同步…

三维视觉传感器的类型

三角法测量原理 视觉传感器的坐标系统 单一摄像机二维传感器 点结构光视觉传感器 线结构光视觉传感器 条纹结构光视觉传感器 条纹编码三维视觉传感器 彩色编码视觉传感器 被动双目视觉传感器 编码照明双目视觉传感器

传感器sensor

传感器分类 转换原理 传感器名称 典型应用 转换形式 中间参量 电 参 数 电 阻 移动电位器角点 改变电阻 电位器传感器 位移 改变电阻丝或片尺寸 电阻丝应变传感器、半导体应变传感器 微应变、力、负荷 利用电阻的温度效应 热丝传感器 气流速度、液体流量 电阻…

多任务多传感器数据融合实现3D目标检测

转载自:自动驾驶之心 01 引言 本文介绍一篇uber公司在CVPR上发表的一篇论文,即使用多种传感器(LiDAR和RGB相机)数据,以及多任务进行数据融合,实现准确高效的3D目标检测。简而言之,自动驾驶领域…

压力传感器

压力传感器 压力传感器是最常用的一种传感器,其应用范围有各种工业互通环境,涉及航空,航天,军工,石化,电力等。按照不同的测试,压力类型可分表压传感器,差压传感器,绝压…