用Rust智能指针实现单向链表的插入删除

C++链表翻转:头插法原理与实现详解 链表是数据结构中的基础概念,通过节点和指针实现动态内存管理。其核心优势在于O(1)时间复杂度的插入/删除操作,这使其在日志系统、浏览器历史记录等需要频繁修改数据的场景中具有重要价值。头插法作为链表翻转的经典算法,通过逐个移动节点到新链表头部实现逆序,仅需O(n)时间复杂度和O(1)空间复杂度。在C++实现中尤其需要注意指针操作和边界条件处理,这是理解内存管理和提升算法能力的关键。该技术广泛应用于加密算法、大数据处理等需要逆序操作的工程场景,也是面试中检验候选人基本功的常见考点。 阅读详情

最近在熟悉Rust,都说链表是Rust的第一个坑,今天尝试用智能指针实现一个单向链表的常见操作:头部插入、删除,尾部插入、删除,中间插入、删除,链表反转。

首先定义链表节点:

#[derive(Debug)]
struct Node {
    value: i32,
    next: Option<Box<Node>>,
}

节点方法:

impl Node {
    fn new(value: i32) -> Box<Node> {
        Box::new(Node { value, next: None })
    }

    fn link(&mut self, node: Box<Node>) {
        self.next = Some(node);
    }
}

链表结构体:

#[derive(Debug)]
struct BoxedLinkedList {
    head: Option<Box<Node>>,
}

链表常见操作:

#[allow(unused)]
impl BoxedLinkedList {
    fn new() -> BoxedLinkedList {
        BoxedLinkedList { head: None }
    }

    fn is_empty(&self) -> bool {
        self.head.is_none()
    }

    fn push_front(&mut self, value: i32) {
        let mut new_node = Node::new(value);
        if let Some(node) = self.head.take() {
            new_node.link(node);
        }

        self.head = Some(new_node);
    }

    fn pop_front(&mut self) -> Option<i32> {
        match self.head.take() {
            None => None,
            Some(node) => {
                self.head = node.next;
                Some(node.value)
            }
        }
    }

    fn push_back(&mut self, value: i32) {
        let new_node = Node::new(value);
        match self.head.as_mut() {
            None => self.head = Some(new_node),
            Some(mut curr) => {
                while curr.next.is_some() {
                    curr = curr.next.as_mut().unwrap();
                }
                curr.link(new_node);
            }
        }
    }

    fn pop_back(&mut self) -> Option<i32> {
        match self.head.as_mut() {
            None => None,
            Some(mut curr) => {
                while curr.next.is_some() && curr.next.as_ref().unwrap().next.is_some() {
                    curr = curr.next.as_mut().unwrap();
                }
                match curr.next {
                    Some(_) => Some(curr.next.take().unwrap().value),
                    None => Some(self.head.take().unwrap().value),
                }
            }
        }
    }

    // 按从小到大顺序插入
    fn insert(&mut self, value: i32) {
        let mut new_node = Node::new(value);
        match self.head.as_mut() {
            None => self.head = Some(new_node),
            Some(mut curr) => {
                if value <= curr.value {
                    self.push_front(value);
                } else {
                    while curr.next.is_some() && curr.next.as_ref().unwrap().value < value {
                        curr = curr.next.as_mut().unwrap();
                    }

                    if let Some(node) = curr.next.take() {
                        new_node.link(node);
                    }
                    curr.next = Some(new_node);
                }
            }
        }
    }

    fn delete(&mut self, value: i32) -> bool {
        match self.head.as_mut() {
            None => false,
            Some(mut curr) => {
                if curr.value == value {
                    self.head = self.head.take().unwrap().next;
                    true
                } else {
                    while curr.next.is_some() && curr.next.as_ref().unwrap().value != value {
                        curr = curr.next.as_mut().unwrap();
                    }

                    match curr.next.take() {
                        None => false,
                        Some(node) => {
                            curr.next = node.next;
                            true
                        }
                    }
                }
            }
        }
    }

    fn reverse(&mut self) {
        if self.is_empty() || self.head.as_ref().unwrap().next.is_none() {
            return;
        }

        let mut left = self.head.as_mut().unwrap().next.take();
        while left.is_some() {
            let mut t = left.take().unwrap();
            left = t.next;
            t.next = self.head.take();
            self.head = Some(t);
        }
    }
}

 

 

如何用Rust实现高性能LRU缓存? 本文的目标是帮助开发者掌握“如何用Rust实现一个高性能LRU缓存”。LRU缓存的核心原理(为什么需要双向链表+哈希表)Rust中数据结构的选择(为什么不用标准库的LinkedList?高性能优化技巧(减少内存分配、避免锁竞争)完整的Rust代码实现与逐行解析单元测试验证LRU行为用生活案例理解LRU的核心思想拆解LRU的经典数据结构组合(哈希表+双向链表)用Rust实现基础LRU缓存(含代码逐行解析)优化性能(替换为更高效的哈希表和链表结构)编写单元测试验证功能正确性。 阅读详情

相关推荐

掌握Rust实现高级链表技术——linked-listrs项目解析

Rust引入了生命周期(lifetimes)的概念,用以描述不同值的引用如何相互关联。生命周期确保引用始终有效。编译器使用生命周期来防止悬挂引用,即在数据可能不再有效时仍在使用它的引用。生命周期注解有助于在编译器分析代码时指出哪些引用是有效的,哪些不是。它们看起来像这样:'a'b等。// 生命周期注解示例x} else {y在上面的代码中,longest函数有两个字符串切片作为参数,并返回它们中最长的一个。生命周期注解'a。

weixin_34779181的博客 837

Rust 双向链表 LinkedList 和安全删除元素的方法

一旦找到要删除的元素,你可以通过调整相邻节点的指针来将其从链表中移除,这个过程的时间复杂度是O(1)。一种常见的做法是使用“安全”的删除方法,比如在迭代过程中收集要删除的元素的索引或引用,然后在循环结束后再进行实际的删除操作。请记住,双向链表的性能特征意味着在链表的中间插入或删除元素可能比在数组的对应位置进行相同的操作更加低效,因为链表必须遍历节点直到找到所需的位置。在双向链表的头部或尾部删除元素通常是一个相对高效的操作,因为这两个位置都保留了直接的指针引用,可以直接调整指针来移除元素,无需遍历整个链表。

程序猿视角 2413

rust-linked-list:在 Rust 中实现简单的链表,这样我就可以学习 Rust

锈链表 在 rust 中实现简单的链表,这样我就可以学习 rust。

Rust每日一练(Leetday0007) 删除结点、有效括号、合并链表

19. 删除链表的倒数第 N 个结点 Remove-nth-node-from-end-of-list🌟🌟   20. 有效的括号 Valid Parentheses🌟   21. 合并两个有序链表 Mmerge-two-sorted-lists🌟

汉阳Hann's Home 570

leetcode:移除链表元素 python解法

移除链表元素 1.题目说明 题目要求:删除链表中等于给定值 val 的所有节点。 示例: 输入: 1->2->6->3->4->5->6, val = 6 输出: 1->2->3->4->5 2.思路说明. 首先,初始化一个值为-1的dummy结点,指向head结点。 然后,逐个遍历,当遇到当前结点指向的next结点的值与val相等时,当前指针指向下一个结点的next。 最后,链表遍历结束,返回链表。 python代码如下: ## Python 代码 # Definition for singly-linked list. # class ListNode: # d

【dify】 dify环境变量配置说明

SMTP_SERVER、SMTP_PORT、SMTP_USERNAME、SMTP_PASSWORD、SMTP_USE_TLS、SMTP_OPPORTUNISTIC_TLS:当 MAIL_TYPE 为 smtp 时,SMTP服务器的相关配置。UPLOAD_IMAGE_FILE_SIZE_LIMIT、UPLOAD_VIDEO_FILE_SIZE_LIMIT、UPLOAD_AUDIO_FILE_SIZE_LIMIT:分别为上传图像、视频、音频文件的大小限制(MB)。

tonysh_zds的博客 7357

算法leetcode|92. 反转链表 II(rust重拳出击)

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left

二当家的白帽子 3377

SAP 深入理解库存

当 某个期间发生货物移动的时候,系统在更新mard数据的之前(这个表是实时更新的),会检查此笔业务过账期间和mard里对应记录的期间是否一致,也就是 看这是不是本期间第一笔移动。其二,我们不能保证这定期的作业的确定性,硬件维护、系统性能都可能使这预定的“时刻”出现偏差,如果某一次没能抓取该时刻的库存,对整个报表来说,是数据的缺失;中,当某一期间(Period)的第一项操作更新了物料数量或价值,则SAP系统会向表MBEWH写入一条记录,以第一项操作之前的余额、价格控制为标准。这对于业务数据量大的。

matinal 當冬夜漸暖 。公众号:matinal 3624

206. 反转链表

题目描述: 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 示例 1: 输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1] 示例 2: 输入:head = [1,2] 输出:[2,1] 示例 3: 输入:head = [] 输出:[] 提示: 链表中节点的数目范围是 [0, 5000] -5000 <= Node.val <= 5000 进阶:链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题? 来...

weixin_43098069的博客 883

技术解析:ChangeFormer——基于Transformer的孪生网络在遥感变化检测中的创新应用

本文深入解析了ChangeFormer模型在遥感变化检测中的创新应用,该模型基于Transformer架构和孪生网络(Siamese Network),显著提升了变化检测的精度和效率。通过详细的技术实现和实战经验分享,展示了其在建筑物变化、森林监测等场景中的卓越表现,为相关领域的研究和应用提供了有力工具。

weixin_29102619的博客 497

CTFmisc-------Jack

每一个文件里面都有不一样的base64编码,我尝试将其解密,发现解出来的是乱码,所以我想到真正的flag藏在这些字符串中,所以我们要写代码把字符串提取出来。提取出来后,得到很多的base64的编码,要一个一个的解码很麻烦,猜到里面有flag字样的base64编码,所以我们将flag进行base64编码,1.下载得到Jack文件夹,里面有很多的txt文件。发现这个字符串是众多编码中唯一一个没有==然后从那些base编码中寻找Zmxh字段。

woshicainiao666的博客 1万+

Rust学习笔记(16)——单向链表之四:链表的遍历和反转

前几篇学习了插入和删除等操作,再尝试实现一下遍历和翻转。 一、遍历 遍历的实现比较简单,从头节点开始逐个后移即可。下面是一个比较简单的实现,只是依次打印出节点的值。 impl BoxedLinkedList { fn traverse(&self) { let mut curr = self.head.as_ref(); while curr.is_some() { print!("{:?}\t", curr.unwrap().

Konquerx的博客 1274

ABAP Bits and Bytes 完全参考,理解内存、字节、位运算与类型解释

ABAP开发中业务代码与底层字节处理的差异:业务层关注采购订单、会计凭证等语义信息,而接口开发需处理十六进制、位运算等底层操作。文章通过整数变量示例说明同一段字节在不同类型解释下会呈现不同值,并介绍x类型、位运算及类型转换的实际应用。这些知识在文件接口、加密传输等场景中尤为重要,开发者需注意字节序、编码等问题。建议将底层协议处理与业务逻辑分离,以保持代码清晰和可维护性。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 142

Rust学习笔记(13)——struct、Option和Box组合应用实现单向链表

前面深入学习了struct、Option和Box的所有权约束及各种场景的使用,现在用struct、Option和Box组合来实现一个单向链表,并实现链表常见的头部插入、删除,尾部插入、删除,中间插入、删除,链表反转,遍历等操作。 一、链表和节点定义 为了方便演示,我们先定义节点,以及节点的new 和link操作,然后再定义一个链表结构体,其中仅有一个头指针成员。 1.1 先定义节点及节点的new / link 操作 #[derive(Debug)] struct Node { val: i

Konquerx的博客 1480

STM32CubeMX之DAC产成正弦波

“在之前的文章中曾经介绍过用TIM产生PWM做DAC用,STM32定时器输出PWM做DAC。部分型号的STM32单片机内部有专用的DAC,本篇文章将介绍如何用内部DAC+DMA产生正弦波...

zhang062061的专栏 1513

一分钟了解 “提示词工程”、“上下文工程”、“驾驭工程”

在大模型刚刚进入大众视野的初期,开发者面临的最大挑战是如何让模型听懂人类的指令。这一阶段被称为提示词工程时代。其核心思想非常直观:通过精心设计输入的文本提示,引导模型输出符合预期的结果。这一时期的开发者更像是“提示词巫师”,他们热衷于寻找所谓的“魔法咒语”。典型的技巧包括角色设定、思维链、少样本学习以及输出格式约束。例如,仅仅在问题前加上一句“请一步步思考”,模型的推理能力往往就能得到显著提升。然而,随着应用场景的复杂化,提示词工程的局限性逐渐暴露。

h a 6 6 6 c k 为 你解决复杂难题! 570

Rust开发之链表的实现与基本操作(单链表、双向链表)

在本案例中,我们完成了链表这一经典数据结构在 Rust 中的安全实现✅单向链表使用Box<T>和Option<T>实现,完全由编译器保证内存安全;✅双向链表借助和Weak<T>解决共享可变性问题,避免了循环引用导致的内存泄漏;✅ 掌握了take()upgrade()等关键方法的实际应用场景;✅ 通过对比表格明确了不同类型链表的优劣与适用场景;✅ 设计了分阶段的学习路径,帮助读者由浅入深掌握复杂数据结构开发技巧。

风中追风 1050

SerDes学习笔记:接收机CTLE均衡架构示例(USB3.1、PCIe3.0\4.0\5.0)

本文分析了USB3.1和PCIe标准中连续时间线性均衡器(CTLE)的设计演进。USB3.1Gen1采用一阶CTLE,其传递函数在长信道下具有有源滤波器特性;Gen2版本延续类似架构,通过Adc参数调节零点频率。PCIeGen3/4保持一阶结构但调整极点位置,Gen5升级为二阶传递函数,扩展Adc调节范围至-5dB~-15dB。研究表明,CTLE能有效改善信号完整性,通过参数优化可平衡信号衰减与码间干扰抑制。

一只豌豆象的博客 626

Rust 练习册 :从零开始实现链表数据结构

本文介绍了在Rust中实现单向链表的方法。链表是一种线性数据结构,通过指针连接节点,具有动态大小和高效插入/删除的特点。文章详细阐述了Rust实现中的关键点:使用Box<T>进行堆分配,Option<T>处理空指针,以及如何实现基本操作(push、pop、peek等)。特别强调了Rust的所有权系统和内存安全特性在链表实现中的应用。最后通过测试案例验证了实现的正确性,展示了新链表初始为空,push操作能正确增加长度等功能。

w13954856422的博客 1822

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Rust 练习册 8:链表实现与所有权管理

本文介绍了如何在Rust中实现链表数据结构,重点探讨了所有权管理和递归类型问题。通过三个渐进版本展示了链表实现:基础版本使用自定义枚举和mem::replace;优化版本改用Option<T>类型;最终版本利用Option::take()简化代码。

少湖说 734

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Rust Rosetta Code数据结构:链表、树和图在Rust中的优雅实现

Rust Rosetta Code项目提供了丰富的算法和数据结构实现,本文将深入探讨Rust中链表、树和图的优雅实现方式,帮助开发者掌握Rust内存安全和性能优化的核心优势。 ## 📚 数据结构在Rust中的独特魅力 Rust以其内存安全和零成本抽象著称,在数据结构实现方面展现出独特的优势。通过所有权系统和类型系统,Rust确保了数据结构操作的安全性和高效性,同时保持了代码的清晰可读性。

gitblog_00071的博客 520

终极指南:如何在Rust中高效实现LeetCode三大核心数据结构

在算法学习和面试准备中,数据结构是实现高效算法的基石。今天我们来深入探讨leetcode-rust项目中三种最核心的数据结构实现:**HashMap、链表与二叉树**。这些数据结构不仅是LeetCode高频考点,更是Rust语言特性的绝佳实践场景。 ## 🔍 HashMap在Rust中的巧妙应用 HashMap是Rust标准库中最重要的数据结构之一,在leetcode-rust项目中得到了广

gitblog_00727的博客 473

Rust能力养成系列之(40):内存管理:智能指针

前言 管理原始指针是充满风险的,开发人员在使用它们时需要消息处理很多细节。无意的误用会导致内存泄漏、悬置引用和双重释放(memory leaks, dangling references, and double frees)等问题。为了缓解这些问题,可以使用智能指针(smart pointer),这种方法起源自C++。 Rust中有多种智能指针。之所以称为智能,是因为还有额外的元数据和与之相关的代码,会在创建或销毁时参照和执行这些数据和代码。当智能指针超出作用域时,能够自动释放底层资源,而这是智能指针的

qq_40433634的博客 415

Rust LinkedList 的双向链表结构:在安全与灵活之间的精妙平衡

Rust中的双向链表:安全与性能的权衡 Rust标准库的LinkedList<T>通过unsafe代码实现了经典双向链表结构,巧妙解决了所有权循环引用的难题。虽然其API保证内存安全,但在实际应用中存在显著性能局限: 内存局部性差:分散的堆分配节点导致缓存失效频繁 API限制:缺乏稳定节点引用影响某些算法效率 分配开销:每个节点独立分配带来性能损耗 基准测试表明,对多数场景Vec<T>性能更优。LinkedList仅适用于特定需求:O(1)位置操作、分割合并或大元素移动场景。开发者应

liuzhang9的博客 1420

驾驭复杂:Rust 中处理复杂数据结构的专业实践与深度思考 [特殊字符]

Rust处理复杂数据结构时面临独特挑战,主要源于其严格的所有权系统。文章分析了三种解决方案:1) 使用索引代替引用的Arena模式;2) 采用智能指针(Rc/RefCell)实现共享所有权;3) 在必要情况下使用unsafe代码。特别强调Rc与Weak指针配合处理循环引用,以及"不安全内核+安全外壳"的设计哲学。这些方法体现了Rust的核心思想:在保证内存安全的前提下,通过不同方式表达数据关系,而非简单绕过规则。每种方案都需权衡性能、安全性和开发复杂度。

q365107252qq的博客 568

Rust中LinkedList的双向链表结构深度解析

与传统语言不同,Rust的所有权系统使得实现链表这种自引用数据结构充满挑战,因为每个节点需要同时被前驱和后继节点引用,这直接违背了Rust"一个值只能有一个所有者"的核心原则。核心挑战在于维护链表的不变性:每个节点的前驱指针必须正确指向前一个节点,后继指针必须正确指向下一个节点,且链表的头尾指针必须始终一致。当我们需要同时修改相邻节点时,会产生多个可变引用,这在安全Rust中是禁止的。更重要的是,链表的每个元素都需要额外的两个指针开销(在64位系统上为16字节),缓存局部性也远不如连续内存的。

qq_35598850的博客 325
上一篇: 关于项目管理与项目经理
下一篇: Rust指针学习笔记(1)——简单类型
Codevalley
博客等级 码龄9年 22粉丝 27原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值