当前位置: 首页 > 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类来…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强&#xff0c;React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 &#xff08;1&#xff09;使用React Native…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

python报错No module named ‘tensorflow.keras‘

是由于不同版本的tensorflow下的keras所在的路径不同&#xff0c;结合所安装的tensorflow的目录结构修改from语句即可。 原语句&#xff1a; from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后&#xff1a; from tensorflow.python.keras.lay…...

九天毕昇深度学习平台 | 如何安装库?

pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子&#xff1a; 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

数据挖掘是什么?数据挖掘技术有哪些?

目录 一、数据挖掘是什么 二、常见的数据挖掘技术 1. 关联规则挖掘 2. 分类算法 3. 聚类分析 4. 回归分析 三、数据挖掘的应用领域 1. 商业领域 2. 医疗领域 3. 金融领域 4. 其他领域 四、数据挖掘面临的挑战和未来趋势 1. 面临的挑战 2. 未来趋势 五、总结 数据…...

自定义线程池1.2

自定义线程池 1.2 1. 简介 上次我们实现了 1.1 版本&#xff0c;将线程池中的线程数量交给使用者决定&#xff0c;并且将线程的创建延迟到任务提交的时候&#xff0c;在本文中我们将对这个版本进行如下的优化&#xff1a; 在新建线程时交给线程一个任务。让线程在某种情况下…...