当前位置: 首页 > news >正文

从零开始实现一个双向循环链表:C语言实战

文章目录

  • 1链表的再次介绍
  • 2为什么选择双向循环链表?
  • 3代码实现:从初始化到销毁
    • 1. 定义链表节点
    • 2. 初始化链表
    • 3. 插入和删除节点
    • 4. 链表的其他操作
    • 5. 打印链表和判断链表是否为空
    • 6. 销毁链表
  • 4测试代码
  • 5链表种类介绍
  • 6链表与顺序表的区别
  • 7存储金字塔
    • L0: 寄存器
    • L1: 高速缓存(SRAM)
    • L2: 高速缓存(SRAM)
    • L3: 高速缓存(SRAM)
    • L4: 主存(DRAM)
    • L5: 本地二级存储(本地磁盘)
    • L6: 远程二级存储
    • 缓存利用率与局部性原理:
  • 8书籍推荐《深入理解计算机系统》
  • 9新年快乐,代码相伴

1链表的再次介绍

在计算机科学中,链表是一种常见的数据结构,它通过节点之间的指针连接来存储数据。链表有许多变种,其中双向循环链表因其独特的结构而备受关注。今天,我们将通过C语言实现一个双向循环链表,并探讨其核心操作。无论你是数据结构的新手,还是想巩固基础的老手,这篇文章都将为你提供实用的知识和代码示例。
链接: 单链表介绍

2为什么选择双向循环链表?

双向循环链表是一种特殊的链表,它的每个节点都有两个指针:一个指向前一个节点,另一个指向后一个节点。与单向链表不同,双向链表可以从任意一个节点向前或向后遍历。而循环链表的特点是其尾节点指向头节点,形成一个闭环。这种结构在某些场景下非常有用,比如实现高效的队列或缓存机制。

3代码实现:从初始化到销毁

1. 定义链表节点

首先,我们需要定义链表节点的结构。每个节点包含三个部分:

data:存储节点的数据。

next:指向下一个节点的指针。

prev:指向前一个节点的指针。

typedef int LTDataType;typedef struct ListNode
{struct ListNode* next;struct ListNode* prev;LTDataType data;
} LTNode;

2. 初始化链表

链表的初始化是创建一个头节点,并将其next和prev指针指向自己,形成一个空的双向循环链表。

LTNode* BuyListNode(LTDataType x)
{LTNode* New = (LTNode*)malloc(sizeof(LTNode));if (New == NULL){perror("malloc");exit(-1);}New->next = NULL;New->prev = NULL;New->data = x;return New;
}
LTNode* LTInit()
{LTNode* phead = BuyListNode(-1); // 创建头节点phead->next = phead;phead->prev = phead;return phead;
}

3. 插入和删除节点

在双向循环链表中,插入和删除节点是非常高效的操作。我们可以在任意位置插入或删除节点,只需调整相邻节点的指针即可。

插入节点

void LTInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* prev = pos->prev;LTNode* new = BuyListNode(x);prev->next = new;new->prev = prev;new->next = pos;pos->prev = new;
}

删除节点

void LTErase(LTNode* pos)
{assert(pos);LTNode* prev = pos->prev;LTNode* next = pos->next;prev->next = next;next->prev = prev;free(pos);
}

4. 链表的其他操作

我们还实现了一些常见的链表操作,如LTPushBack(在链表尾部插入节点)、LTPopBack(删除链表尾部节点)、LTPushFront(在链表头部插入节点)和LTPopFront(删除链表头部节点)。这些操作都依赖于LTInsert和LTErase函数。

void LTPushBack(LTNode* phead, LTDataType x)
{assert(phead);LTInsert(phead, x);
}void LTPopBack(LTNode* phead)
{assert(phead);LTErase(phead->prev);
}void LTPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTInsert(phead->next, x);
}void LTPopFront(LTNode* phead)
{assert(phead);LTErase(phead->next);
}

5. 打印链表和判断链表是否为空

为了方便调试和观察链表的状态,我们实现了LTPrint函数来打印链表中的所有节点数据。此外,LTEmpty函数用于判断链表是否为空。

void LTPrint(LTNode* phead)
{assert(phead);LTNode* cur = phead->next;printf("<=phead=>");while (cur != phead){printf("%d<=>", cur->data);cur = cur->next;}puts("");
}bool LTEmpty(LTNode* phead)
{assert(phead);return phead == phead->next;
}

6. 销毁链表

在使用完链表后,我们需要释放所有节点的内存,避免内存泄漏。

void LTDestroy(LTNode* phead)
{assert(phead);LTNode* cur = phead->next;while (cur != phead){LTNode* next = cur->next;free(cur);cur = next;}free(phead);
}

4测试代码

为了验证我们的双向循环链表实现是否正确,我们编写了一个简单的测试函数Test1。在这个函数中,我们进行了多次插入、删除操作,并打印链表的状态。

void Test1()
{LTNode* phead = LTInit();LTPushBack(phead, 2);LTPushBack(phead, 1);LTPushFront(phead, 5);LTPrint(phead);LTInsert(phead->next, 6);LTInsert(phead->next, 6);LTPushFront(phead, 6);LTPrint(phead);LTPopBack(phead);LTPopBack(phead);LTPopFront(phead);LTErase(phead->next);LTPrint(phead);LTPushBack(phead, 4);LTPushBack(phead, 3);LTPushBack(phead, 2);LTPushBack(phead, 1);LTPrint(phead);printf("%d\n", LTEmpty(phead));LTDestroy(phead);phead = LTInit();printf("%d\n", LTEmpty(phead));
}int main()
{Test1();return 0;
}

5链表种类介绍

在这里插入图片描述
在这里插入图片描述

6链表与顺序表的区别

在这里插入图片描述

7存储金字塔

在这里插入图片描述
这张图片展示了计算机存储体系的层级结构,通常被称为存储金字塔(Memory Hierarchy)。它描述了不同层级的存储设备从最快速但成本最高到最慢但成本最低的分布情况。每一层级的存储设备都具有不同的访问速度和成本,它们相互配合,以实现性能和成本的最佳平衡。
存储金字塔层级介绍:

L0: 寄存器

位于金字塔的顶端,是CPU内部的寄存器,提供最快的数据访问速度。
寄存器的数量有限,因此它们用于存储最频繁访问的数据。

L1: 高速缓存(SRAM)

位于寄存器下方,是CPU的一级缓存,使用静态随机存取存储器(SRAM)。
L1缓存分为两个部分:L1指令缓存(L1-I)和L1数据缓存(L1-D),分别用于存储指令和数据。

L2: 高速缓存(SRAM)

二级缓存通常集成在CPU芯片上,或者在某些设计中位于CPU芯片附近。
L2缓存比L1缓存大,但访问速度稍慢。

L3: 高速缓存(SRAM)

三级缓存是更大但速度较慢的缓存层级,通常位于CPU芯片外。
L3缓存为多个核心共享,用于减少核心之间的数据访问延迟。

L4: 主存(DRAM)

主存储器,即动态随机存取存储器(DRAM),是计算机的主要内存。
与缓存相比,主存的访问速度较慢,但容量更大,成本更低。

L5: 本地二级存储(本地磁盘)

本地磁盘,如硬盘驱动器(HDD)或固态硬盘(SSD),用于长期存储数据。
访问速度比主存慢得多,但存储容量更大,成本更低。

L6: 远程二级存储

远程存储,如分布式文件系统、网络附加存储(NAS)或Web服务器,提供更大的存储空间。
访问速度最慢,但可以提供几乎无限的存储容量。

缓存利用率与局部性原理:

缓存利用率:指的是缓存中存储的数据被访问的频率。高缓存利用率意味着更多的数据访问可以直接从缓存中获取,从而提高系统性能。
局部性原理:包括时间局部性和空间局部性。时间局部性指的是最近访问过的数据很可能在不久的将来再次被访问;空间局部性指的是如果一个数据被访问,那么它附近的数据也很可能被访问。缓存的设计就是基于这些原理,以提高缓存利用率。

8书籍推荐《深入理解计算机系统》

链接: 书籍介绍

9新年快乐,代码相伴

在这个充满希望的新年里,愿你的代码之旅充满乐趣和挑战。无论是探索数据结构的奥秘,还是深入理解计算机系统的运行机制,都希望你能收获满满。让我们一起在代码的世界里,继续探索、学习和成长,用代码书写属于自己的精彩篇章。

相关文章:

从零开始实现一个双向循环链表:C语言实战

文章目录 1链表的再次介绍2为什么选择双向循环链表&#xff1f;3代码实现&#xff1a;从初始化到销毁1. 定义链表节点2. 初始化链表3. 插入和删除节点4. 链表的其他操作5. 打印链表和判断链表是否为空6. 销毁链表 4测试代码5链表种类介绍6链表与顺序表的区别7存储金字塔L0: 寄存…...

MYSQL面试题总结(题目来源JavaGuide)

MYSQL基础架构 问题1&#xff1a;一条 SQL语句在MySQL中的执行过程 1. 解析阶段 (Parsing) 查询分析&#xff1a;当用户提交一个 SQL 语句时&#xff0c;MySQL 首先会对语句进行解析。这个过程会检查语法是否正确&#xff0c;确保 SQL 语句符合 MySQL 的语法规则。如果发现…...

visual studio安装

一、下载Visual Studio 访问Visual Studio官方网站。下载 Visual Studio Tools - 免费安装 Windows、Mac、Linux 在主页上找到并点击“下载 Visual Studio”按钮。 选择适合需求的版本&#xff0c;例如“Visual Studio Community”&#xff08;免费版本&#xff09;&#x…...

JVM执行引擎

一、执行引擎的概述: 执行引擎是]ava虚拟机核心的组成部分之一; “虚拟机”是一个相对于“物理机”的概念&#xff0c;这两种机器都有代码执行能力&#xff0c;其区别是物理机的执行引擎是直接建立在处理器、缓存、指令集和操作系统层面上的&#xff0c;而虚拟机的执行引擎则…...

C# 9.0记录类型:解锁开发效率的魔法密码

一、引言&#xff1a;记录类型的神奇登场 在 C# 的编程世界中&#xff0c;数据结构就像是构建软件大厦的基石&#xff0c;其重要性不言而喻。然而&#xff0c;传统的数据结构定义方式&#xff0c;尤其是在处理简单的数据承载对象时&#xff0c;常常显得繁琐复杂。例如&#xf…...

搭建自己的专属AI——使用Ollama+AnythingLLM+Python实现DeepSeek本地部署

前言 最近DeepSeek模型非常火&#xff0c;其通过对大模型的蒸馏得到的小模型可以较轻松地在个人电脑上运行&#xff0c;这也使得我们有机会在本地构建一个专属于自己的AI&#xff0c;进而把AI“调教”为我们希望的样子。本篇文章中我将介绍如何使用OllamaAnythingLLMPython实现…...

『 C++ 』中理解回调类型在 C++ 中的使用方式。

文章目录 案例 1&#xff1a;图形绘制库中的回调使用场景说明代码实现代码解释 案例 2&#xff1a;网络服务器中的连接和消息处理回调场景说明代码实现代码解释 案例 3&#xff1a;定时器中的回调使用场景说明代码实现代码解释 以下将通过不同场景给出几个使用回调类型的具体案…...

git多人协作

目录 一、项目克隆 二、 1、进入克隆仓库设置 2、协作处理 3、冲突处理 4、多人协作分支的推送拉取删除 1、分支推送&#xff08;2种&#xff09; 2、远程分支拉取&#xff08;2种&#xff09; 3、远程分支删除 一、项目克隆 git clone 画船听雨眠/test1 (自定义的名…...

CTFSHOW-WEB入门-命令执行71-77

题目&#xff1a;web 71 题目&#xff1a;解题思路&#xff1a;分析可知highlight_file() 函数被禁了&#xff0c;先想办法看看根目录&#xff1a;cvar_export(scandir(dirname(‘/’))); 尝试一下发现很惊奇&#xff1a;&#xff08;全是&#xff1f;&#xff09;这种情况我也…...

浅谈《图解HTTP》

感悟 滑至尾页的那一刻&#xff0c;内心突兀的涌来一阵畅快的感觉。如果说从前对互联网只是懵懵懂懂&#xff0c;但此刻却觉得她是如此清晰而可爱的呈现在哪里。 介绍中说&#xff0c;《图解HTTP》适合作为第一本网络协议书。确实&#xff0c;它就像一座桥梁&#xff0c;连接…...

LLMs瞬间获得视觉与听觉感知,无需专门训练:Meta的创新——在图像、音频和视频任务上实现最优性能。

引言&#xff1a; 问题&#xff1a; 当前的多模态任务&#xff08;如图像、视频、音频描述生成、编辑、生成等&#xff09;通常需要针对特定任务训练专门的模型&#xff0c;而现有的方法在跨模态泛化方面存在局限性&#xff0c;难以适应新任务。此外&#xff0c;多模态嵌入反演…...

自研有限元软件与ANSYS精度对比-Bar3D2Node三维杆单元模型-央视大裤衩实例

目录 1、“央视大裤衩”自研有限元软件求解 1.1、选择单元类型 1.2、导入“央视大裤衩”工程 1.3、节点坐标定义 1.4、单元连接关系、材料定义 1.5、约束定义 1.6、外载定义 1.7、矩阵求解 1.8、变形云图展示 1.9、节点位移 1.10、单元应力 1.11、节点支反力 2、“…...

kubernetes 高可用集群搭建

在生产环境中部署 Kubernetes 集群时&#xff0c;确保其高可用性&#xff08;High Availability, HA&#xff09;是至关重要的。高可用性不仅意味着减少服务中断时间&#xff0c;还能提高系统的稳定性和可靠性。本文将详细介绍如何搭建一个高可用的 Kubernetes 集群&#xff0c…...

【C++】STL——vector底层实现

目录 &#x1f495; 1.vector三个核心 &#x1f495;2.begin函数&#xff0c;end函数的实现&#xff08;简单略讲&#xff09; &#x1f495;3.size函数&#xff0c;capacity函数的实现 &#xff08;简单略讲&#xff09; &#x1f495;4.reserve函数实现 &#xff08;细节…...

数据结构初探:链表之单链表篇

本文图皆为作者手绘,所有代码基于vs2022运行测试 系列文章目录 数据结构初探:顺序表篇 文章目录 系列文章目录前言一、链表基础概念二、链表的分类简化边界条件处理使代码更清晰简洁提高程序稳定性 1.单链表(不带头不循环的单链表);1.1存储结构;1.2准备工作1.3链表增删查改的实…...

介绍一下Mybatis的底层原理(包括一二级缓存)

表面上我们的就是Sql语句和我们的java对象进行映射&#xff0c;然后Mapper代理然后调用方法来操作数据库 底层的话我们就涉及到Sqlsession和Configuration 首先说一下SqlSession&#xff0c; 它可以被视为与数据库交互的一个会话&#xff0c;用于执行 SQL 语句&#xff08;Ex…...

Linux基础 ——tmux vim 以及基本的shell语法

Linux 基础 ACWING y总的Linux基础课&#xff0c;看讲义作作笔记。 tmux tmux 可以干嘛&#xff1f; tmux可以分屏多开窗口&#xff0c;可以进行多个任务&#xff0c;断线&#xff0c;不会自动杀掉正在进行的进程。 tmux – session(会话&#xff0c;多个) – window(多个…...

64位的谷歌浏览器Chrome/Google Chrome

64位的谷歌浏览器Chrome/Google Chrome 在百度搜索关键字:chrome&#xff0c;即可下载官方的“谷歌浏览器Chrome/Google Chrome”&#xff0c;但它可能是32位的&#xff08;切记注意网址&#xff1a;https://www.google.cn/....&#xff0c; 即&#xff1a;google.cn&#xff…...

jetson编译torchvision出现 No such file or directory: ‘:/usr/local/cuda/bin/nvcc‘

文章目录 1. 完整报错2. 解决方法 1. 完整报错 jetson编译torchvision,执行python3 setup.py install --user遇到报错 running build_ext error: [Errno 2] No such file or directory: :/usr/local/cuda/bin/nvcc完整报错信息如下&#xff1a; (pytorch) nxnx-desktop:~/Do…...

多线程创建方式三:实现Callable接口

实现Callable第三种方式存在的原因 作用&#xff1a;可以返回线程执行完毕后的结果。 前两种线程创建方式都存在的一个问题&#xff1a;假如线程执行完毕后有一些数据需要返回,他们重写的run方法均不能直接返回结果。 如何实现 ● JDK 5.0提供了Callable接口和FutureTask类来…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...