单向链表在实际项目中的应用
前言
在实际项目中,单向链表经常被用来解决排队问题,因为链表允许动态地添加和移除元素,非常适合模拟队列(FIFO,先进先出)的行为。
这里的链表包含头节点,头结点的数据用来记录链表长度,该链表支持任意任意位置插入(插队)、尾插(按序排队),依据数据删除(找不到数据则返回错误),依据位置删除(超过链表节点数则返回失败)。
参考数据结构——单向链表-CSDN博客
有纰漏请指出,转载请说明。
学习交流请发邮件 1280253714@qq.com
单向链表在排队应用中的解决方案
单向链表在实际项目中的应用非常广泛,特别是在处理排队问题时,其灵活性和高效性使其成为理想的数据结构之一。以下是一些单向链表在实际项目中应用于排队问题的例子:
1. 订单处理系统
在电商或餐饮等行业中,订单处理系统需要高效地管理大量的订单请求。使用单向链表,可以将新到达的订单添加到链表的尾部,表示订单队列的末尾。处理订单时,可以从链表的头部开始,依次处理每个订单,直到队列为空。这种方式能够确保订单按照到达的顺序被处理,同时支持快速的插入和删除操作。
2. 任务调度系统
在操作系统或分布式系统中,任务调度系统负责管理和分配计算资源给各个任务。使用单向链表,可以将待调度的任务按照优先级或到达时间排序,形成一个任务队列。调度器可以从链表的头部开始,依次选择任务进行调度。当任务完成后,可以从链表中删除该任务节点。这种方式能够确保任务按照预定的顺序被调度,同时支持动态的插入和删除操作。
3. 网络连接管理
在网络通信中,服务器需要管理大量的客户端连接。使用单向链表,可以将每个客户端连接作为一个节点添加到链表中,形成一个连接队列。服务器可以遍历链表,对每个连接进行处理,如发送数据、接收数据或关闭连接等。当有新连接到达时,可以将其添加到链表的尾部;当连接关闭时,可以从链表中删除该节点。这种方式能够高效地管理网络连接,支持快速的插入和删除操作。
4. 事件驱动系统
在事件驱动的应用程序中,如游戏或实时监控系统,事件需要按照发生的时间顺序被处理。使用单向链表,可以将事件按照发生时间排序,形成一个事件队列。事件处理器可以遍历链表,依次处理每个事件。当有新事件到达时,可以将其插入到链表的合适位置,以保持事件的顺序性。这种方式能够确保事件按照正确的时间顺序被处理,同时支持动态的插入操作。
5. 打印机队列管理
在打印系统中,打印机需要管理多个打印任务。使用单向链表,可以将每个打印任务作为一个节点添加到链表中,形成一个打印任务队列。打印机可以遍历链表,依次处理每个打印任务。当有新的打印任务到达时,可以将其添加到链表的尾部;当任务完成后,可以从链表中删除该节点。这种方式能够高效地管理打印任务,确保任务按照到达的顺序被处理。
综上所述,单向链表在实际项目中的应用非常广泛,特别是在处理排队问题时。其灵活性和高效性使其成为管理动态数据集合的理想选择之一。
单向链表操作相关函数
typedef int data_t;typedef struct node {data_t data;struct node * next;
}listNode, * linkList;linkList list_create(void) //创建链表,即头节点
{linkList list;list = (linkList)malloc(sizeof(listNode));//给节点动态分配内存if (list == NULL)//判断是否申请内存成功 {return list;} //如果成功了,则进行赋初值list->data = 0; //一般存放节点个数list->next = NULL;//刚开始时没有节点插入链表,所以该头节点即是尾节点return list; //返回头节点指针
}int list_tail_insert(linkList list, data_t data) //传入待插入的链表地址和待插入的数据
{linkList p = NULL;//定义临时指针变量linkList q = NULL;if (list == NULL) //检验传入的链表是否有效{return -1;}//创建新节点并检查有效性,存放待插入数据if ((p = (linkList)malloc(sizeof(listNode))) == NULL){return -1;}p->data = data;p->next = NULL;q = list;while (q->next != NULL) //遍历链表找尾部{q = q->next;}q->next = p;//插入链表,尾部的next指针指向新节点list->data++;//插入数据后,数据个数加一 return 0;
}// 插入函数,位置从0开始计数
int list_insert_at_position(linkList list, int position, data_t data) {linkList p = NULL; // 新节点指针linkList q = list; // 用于遍历的临时指针linkList prev = NULL; // 用于记录当前节点的前一个节点int i = 0; // 位置计数器// 检查位置是否有效(非负且不大于当前链表长度)if (position < 0) {return -1; // 位置无效}// 创建新节点并检查内存分配是否成功if ((p = (linkList)malloc(sizeof(listNode))) == NULL) {return -1; // 内存分配失败}p->data = data;p->next = NULL;if (list->next==NULL && position==0) {list->data = 1;list->next = p;} else{q = q->next; //跳过头节点// 遍历链表找到插入位置while (q != NULL && i < position) {prev = q;q = q->next;i++;}// 检查位置是否超出了链表长度if (i > position) {// 如果i大于position,说明position是在链表尾部或之后的位置,应该插入到尾部prev->next = p;} else {// 否则,插入到指定位置if (prev != NULL) {p->next = q;prev->next = p;} else {// 如果prev是NULL,说明position是0,应该插入到链表头部p->next = list;list = p;}}list->data++;//插入数据后,数据个数加一 }return 0; // 插入成功
}//寻找链表上某一位置的节点的地址,返回该节点地址
linkList list_get_addr(linkList list, int pos) //传入链表指针和待寻找节点的位置
{linkList p = NULL;int i = -1;if (list == NULL) {return NULL;}if (pos == -1) {return list;//如果是-1,则返回链表头节点,因为用0表示第一个节点的位置}p = list;while (i < pos) //遍历寻找{p = p->next;if (p == NULL) //没有到达指定位置,链表已经结尾了,位置错误,返回NULL{return NULL;}i++; }return p;
}int list_deleteBaseOnPos(linkList list, int pos)
{linkList p = NULL;linkList deleteNode = NULL;if (list == NULL) return -1;p = list_get_addr(list, pos-1);//寻找待删除节点的上一个节点if (p == NULL) {return -1;//没有找到则返回}if (p->next == NULL) //如果要删除的节点不存在,则返回{return -1;}deleteNode = p->next;//找到要删除的节点//将待删除的next指针赋给上一个节点的next指针p->next = deleteNode->next;//也可以用p->next = p->next->next;//释放删除节点的内存free(deleteNode);deleteNode = NULL;list->data--;//删除节点后,数据个数减一 return 0;
}int list_deleteBaseOnData(linkList list, data_t data)
{int pos = 0;linkList p = NULL;linkList q = NULL;linkList deleteNode = NULL;if (list == NULL) return -1;q = list->next;while (q->data != data) //遍历链表找相同数据{q = q->next;pos++;if (pos >= list->data){return -1;//没有找到则返回}}p = list_get_addr(list, pos-1);//寻找待删除节点的上一个节点if (p == NULL) {return -1;//没有找到则返回}if (p->next == NULL) //如果要删除的节点不存在,则返回{return -1;}deleteNode = p->next;//找到要删除的节点//将待删除的next指针赋给上一个节点的next指针p->next = deleteNode->next;//也可以用p->next = p->next->next;//释放删除节点的内存free(deleteNode);deleteNode = NULL;list->data--;//删除节点后,数据个数减一 return 0;
}
实例
int main(void)
{ linkList list; list = list_create();//外部调用函数进行创建if (list == NULL)return -1;list_insert_at_position(list,0,7);list_tail_insert(list, 6);//在链表尾部进行插入list_tail_insert(list, 2);//在链表尾部进行插入list_tail_insert(list, 5);//在链表尾部进行插入list_tail_insert(list, 3);//在链表尾部进行插入list_tail_insert(list, 4);//在链表尾部进行插入list_insert_at_position(list,2,1);list_deleteBaseOnData(list, 2);list_deleteBaseOnPos(list, 3);while (1){}
}
仿真结果
变量定义
创建链表
list = list_create();
在第“0”个位置插入数据7
list_insert_at_position(list,0,7);
依次尾插数据6 2 5 3 4
list_tail_insert(list, 6);//在链表尾部进行插入
list_tail_insert(list, 2);//在链表尾部进行插入
list_tail_insert(list, 5);//在链表尾部进行插入
list_tail_insert(list, 3);//在链表尾部进行插入
list_tail_insert(list, 4);//在链表尾部进行插入
在第“2”个位置插入数据1
list_insert_at_position(list,2,1);
找到数据为2的节点并删除
list_deleteBaseOnData(list, 2);
相关文章:

单向链表在实际项目中的应用
前言 在实际项目中,单向链表经常被用来解决排队问题,因为链表允许动态地添加和移除元素,非常适合模拟队列(FIFO,先进先出)的行为。 这里的链表包含头节点,头结点的数据用来记录链表长度&#x…...

【系统架构设计师】操作系统 ③ ( 存储管理 | 页式存储弊端 - 段式存储引入 | 段式存储 | 段表 | 段表结构 | 逻辑地址 的 合法段地址判断 )
文章目录 一、页式存储弊端 - 段式存储引入1、页式存储弊端 - 内存碎片2、页式存储弊端 - 逻辑结构不匹配3、段式存储引入 二、段式存储 简介1、段式存储2、段表3、段表 结构4、段内地址 / 段内偏移5、段式存储 优缺点6、段式存储 与 页式存储 对比 三、逻辑地址 的 合法段地址…...

PDF另存为图片的一个方法
说明 有时需要把PDF的每一页另存为图片。用Devexpress可以很方便的完成这个功能。 窗体上放置一个PdfViewer。 然后循环每一页 for (int i 1; i < pdfViewer1.PageCount; i) 调用 chg_pdf_to_bmp函数获得图片并保存 chg_pdf_to_bmp中调用了PdfViewer的CreateBitmap函数…...
HTML之JavaScript运算符
HTML之JavaScript运算符 1.算术运算符 - * / %除以0,结果为Infinity取余数,如果除数为0,结果为NaN NAN:Not A Number2.复合赋值运算符 - * / %/ 除以0,结果为Infinity% 如果除数为0,结果为NaN NaN:No…...
借助 ListWise 提升推荐系统精排效能:技术、案例与优化策略
目录 一、引言二、ListWise 方法概述三、ListWise 用于精排的优势四、ListWise 样本具体的构建过程4.1 确定样本的上下文4.2 收集候选物品及相关特征4.3 确定物品的真实排序标签4.4 构建样本列表4.5 划分训练集、验证集和测试集 五、ListWise 方法案例分析六、ListWise 方法在精…...

C++中什么时候用. 什么时候用->
学了一年C今天出了一个大岔子,因为太久没有做链表类型题目了,并且STL用惯了今天遇到一题,写的时候发现完全不对劲,搞慌了,首先我们看题目 2. 两数相加 再看我第一次的解答,先不论结果对不对 错的行为有很多…...

从云原生到 AI 原生,谈谈我经历的网关发展历程和趋势
作者:谢吉宝(唐三) 编者按: 云原生 API 网关系列教程即将推出,欢迎文末查看教程内容。本文整理自阿里云智能集团资深技术专家,云原生产品线中间件负责人谢吉宝(唐三) 在云栖大会的精…...
【Python深入浅出】Python3正则表达式:开启高效字符串处理大门
目录 一、正则表达式基础入门1.1 什么是正则表达式1.2 正则表达式的语法规则1.3 特殊字符与转义 二、Python 中的 re 模块2.1 re 模块概述2.2 常用函数与方法2.2.1 re.match()2.2.2 re.search()2.2.3 re.findall()2.2.4 re.sub() 2.3 修饰符(Flags)的使用…...
Vue.js Vue CLI 安装与使用
Vue.js Vue CLI 安装与使用 今天我们来聊聊 Vue CLI 的安装与使用。对于开发 Vue 应用来说,Vue CLI 是一个非常强大的工具,它能帮助你快速创建项目脚手架、配置开发环境、自动化构建流程,从而大大提高开发效率。下面我就和大家一步一步地讲解…...
科技的尽头:在有限与永恒的夹缝中寻找文明的真谛
当人类用燧石点燃第一簇文明之火时,科技发展的齿轮便已开始转动。这个从原始工具到量子计算机的进化历程,既是人类突破生物局限的史诗,也是文明不断自我解构与重构的哲学叙事。站在人工智能与基因编辑并行的时代节点,"科技尽…...

【牛客】动态规划专题一:斐波那契数列
文章目录 DP1 斐波那契数列法1:递归法2:动态规划法3:优化空间复杂度 2.分割连接字符串3. 给定一个字符串s和一组单词dict,在s中添加空格将s变成一个句子 DP1 斐波那契数列 法1:递归 // 递归 #include <iostream>…...
java8、9新特性
JAVA8 Lambda 表达式 (parameters) -> expression 或 (parameters) ->{ statements; } 提供了一种更为简洁的语法,尤其适用于函数式接口。相比于传统的匿名内部类,Lambda 表达式使得代码更为紧凑,减少了样板代码的编写。 它允许将函…...

作业:zuoye
1.闹钟(错的) #include "widget.h" #include "ui_widget.h" #include <QMessageBox>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);// 初始化定时器objTimer new QTimer(th…...
redis底层数据结构——链表
文章目录 定义内部实现总结 定义 链表提供了高效的节点重排能力,以及顺序性的节点访间方式,并且可以通过增删节点来灵活地调整链表的长度。 作为一种常用数据结构,链表内置在很多高级的编程语言里面,因为Redis使用的C语言并没有…...
问题解决 4S 法
在深入研读《像高手一样解决问题》的第二章后,犹如打开了一扇通往高效问题解决领域的新大门,其中所阐述的问题解决 4S 法,更是给人以拨云见日之感。 一、陈述(State):明确问题本质 这是问题解决的起始点&…...
SQL-leetcode—1407. 排名靠前的旅行者
1407. 排名靠前的旅行者 表:Users ---------------------- | Column Name | Type | ---------------------- | id | int | | name | varchar | ---------------------- id 是该表中具有唯一值的列。 name 是用户名字。 表:Rides -------------------…...

机器学习(李宏毅)——Transformer
一、前言 本文章作为学习2023年《李宏毅机器学习课程》的笔记,感谢台湾大学李宏毅教授的课程,respect!!! 读这篇文章必须先了解self-attention,可参阅我上一篇。 二、大纲 Transformer问世原理剖析模型训…...

React进阶之React状态管理CRA
React状态管理&CRA 状态管理理论讲解案例 context 上下文结合状态来维护todoListindex.jsApp.jsTaskList.jsTasksContext.jsAddTask.js Escape 脱围机制refforwardRef(不建议使用) CRA 状态管理 理论讲解 如何针对 effect -> 对action的触发 -&…...
攻克AWS认证机器学习工程师(AWS Certified Machine Learning Engineer) - 助理级别认证:我的成功路线图
引言 当我决定考取AWS认证机器学习工程师 - 助理(AWS Certified Machine Learning Engineer — Associate)级别证书时,我就预料到这将是一段充满挑战但回报颇丰的旅程。跟你说吧,它在这两方面都没让我失望。这项考试面向的是不仅理解机器学习原理,还对AWS生态系统有扎实基…...
前端开发环境
vscde nrm 切换源管理 nvm 切换node版本工具 nodemon node运行js文件热更新 pxcook 易用的自动标注工具, 生成前端代码, 设计研发协作利器,比PS轻量 TypeScript 安装tsc 它的作用就是将ts文件编译为js文件 npm i typescript -g 输入tsc -v能够看到东西,就说明好了 …...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...

Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)
引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...
【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验
Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...

nnUNet V2修改网络——暴力替换网络为UNet++
更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...

实战设计模式之模板方法模式
概述 模板方法模式定义了一个操作中的算法骨架,并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。简单来说,就是在一个方法中定义了要执行的步骤顺序或算法框架,但允许子类…...