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

c# 数据结构 链表篇 有关双向链表的一切

        本人能力有限,如有不足还请斧正

目录

0.双向链表的好处

1.双向链表的分类

2.不带头节点的标准双向链表

节点类:有头有尾

链表类:也可以有头有尾 也可以只有头

头插

尾插

遍历

全部代码

3.循环双向链表

节点类

链表类

头插

尾插

遍历

全部代码


 

0.双向链表的好处

优势维度具体好处说明 / 示例对比单向链表的核心差异
双向遍历能力支持正向(next)和反向(prev)遍历,可灵活选择遍历方向- 可从任意节点出发,向前后两个方向遍历链表
- 例如:实现浏览器历史记录的 “前进 / 后退” 功能,直接通过 prev/next 指针操作
单向链表仅能单向遍历,反向操作需从头重新遍历
插入 / 删除效率已知当前节点时,插入 / 删除操作时间复杂度为 O (1),无需提前获取前驱节点- 插入时,通过当前节点的 prev 指针直接找到前驱,更新前后节点的指针即可
- 删除时,直接通过 prev 和 next 指针连接前后节点,无需遍历查找前驱
单向链表删除 / 插入节点时,若无前驱节点引用,需 O (n) 时间遍历查找前驱
定位便利性可直接通过节点的 prev 指针反向定位前驱节点,无需额外存储或遍历- 在链表中间节点操作时,无需维护额外变量记录前驱
- 例如:实现双向队列(双端队列)的头尾插入 / 删除操作,可直接通过指针快速定位
单向链表需从头遍历才能找到前驱节点,定位效率低
边界操作简化处理头节点和尾节点的插入 / 删除时更简单,无需特殊处理头指针(若带头节点)- 带头节点的双向链表中,头节点和尾节点的操作与中间节点逻辑一致
- 例如:删除头节点时,直接通过头节点的 next 找到第一个数据节点,更新其 prev 为 null(非循环情况)
单向链表删除头节点需单独处理头指针,边界条件易出错
应用场景适配适合需要双向操作或频繁前后移动的场景- 操作系统进程调度队列(需快速调整进程优先级,前后移动节点)
- LRU 缓存淘汰算法(需快速删除最近最少使用节点并插入到头部)
单向链表无法高效支持反向操作,需额外数据结构辅助
数据一致性指针操作更安全,减少空指针异常风险(尤其在循环双向链表中)- 循环双向链表中,头节点 prev 指向尾节点,尾节点 next 指向头节点,避免首尾指针为 null 的情况
- 适合对稳定性要求高的场景(如内核数据结构)
单向链表尾节点 next 为 null,反向遍历时易触发空指针错误
算法灵活性支持更复杂的算法逻辑,如双向搜索、回退操作- 在双向链表中实现 “双指针搜索”(如从头尾同时向中间遍历)
- 支持撤销操作(如文本编辑器的撤销 / 重做,通过双向指针回退历史版本)
单向链表需额外栈结构记录历史节点,增加空间复杂度

1.双向链表的分类

分类标准类型核心特点示意图(简化)典型应用场景
是否带头节点带头节点双向链表- 头部有一个固定的头节点(不存储数据),头节点的next指向第一个数据节点
- 尾节点的prev指向头节点(非循环时头节点prevnull
头节点(H) <-> 数据节点1 <-> 数据节点2 <-> ... <-> 尾节点(T)〔T.prev=H,H.next=数据节点1〕频繁进行插入 / 删除操作的场景(如链表初始化、边界操作更便捷)
(本文演示一)不带头节点双向链表- 直接以第一个数据节点作为头节点,头节点prevnull
- 尾节点nextnull
数据节点1 <-> 数据节点2 <-> ... <-> 尾节点(T)〔T.next=null,数据节点1.prev=null〕内存资源敏感场景(节省头节点空间)
是否循环非循环双向链表- 头节点prevnull,尾节点nextnull
- 链表头尾不相连
null <-> 头节点 <-> ... <-> 尾节点 <-> null单向遍历需求不高,但需双向操作的场景(如文件系统目录结构)
 循环双向链表- 头节点prev指向尾节点,尾节点next指向头节点
- 形成一个环形结构,可从任意节点出发遍历整个链表
头节点(H) <-> ... <-> 尾节点(T) <-> H循环数据处理(如循环缓冲区、操作系统进程调度队列)
节点结构扩展标准双向链表(和第一行重复)- 每个节点包含prev(前驱指针)和next(后继指针)
- 存储单一数据元素
节点: prev <-> data <-> next通用双向操作场景(如浏览器历史记录的前进 / 后退)
(本文不做演示)双向链表带附加属性- 节点额外包含其他属性(如优先级、时间戳等)
- 结构上仍保持双向指针
节点: prev <-> data <-> next <-> extra_attr复杂数据管理(如任务调度链表、带权重的链表)

2.不带头节点的标准双向链表

图解模型

每一个节点类Node 都有三个元素:前项 数据 后项

注意因为c#不用指针 所以所谓Prev和Next指向的都是节点类Node 

节点类:有头有尾

public class Node {public int data;public Node prev;public Node next;public Node(int data, Node prev = null, Node next=null) { this.data = data;this.prev = prev;this.next = next;}
}

链表类:也可以有头有尾 也可以只有头

        这里你可能会有一些疑问 怎么又出现了一个HeadNode和一个TailNode呢?
        这是因为链表类需要这两个去抽象的节点以方便管理

public class DoublyLinkedList {public Node headNode;public Node tailNode;public DoublyLinkedList() {headNode = tailNode = null;}

头插

乾坤大挪移

    public void HeadAdd(int data) {//如果链表为空if (headNode == null) { headNode = tailNode = new Node(data);}//双向链表的特殊性: 修改头节点时,需要把新节点的前项 后项 都挂上Node newNode = new Node(data, null, headNode);headNode.prev = newNode;//改变链表头headNode = newNode;}

尾插

    public void TailAdd(int data) {//如果尾巴为空 说明头也没有 所以下面判断头尾都可以if (headNode  == null){   //if (tailNode ==null)headNode = tailNode = new Node(data);}//双向链表的特殊性: 修改尾节点时,需要把新节点的前项 后项 都挂上Node newNode = new Node(data, tailNode, null);tailNode.next = newNode;//改变链表尾tailNode =newNode ;}

无需遍历找前驱节点 找到Target直接调换其前后指针指向即可

 public void DeleteValue(int data){if (headNode == null) return;Node current = headNode;while (current != null){if (current.data == data){//如果匹配到了则可能出现以下情况://1 删除的是头节点if (current.prev == null)headNode = current.next;//2.删除的是尾巴if (current.next == null)tailNode = current.prev;//3.删除的是中间节点current.prev.next = current.next;current.next.prev = current.prev;return;}current = current.next;}}

查询找到的第一个目标

    public bool SearchValue(int data){if (headNode == null) return true;Node current = headNode;while (current != null){if (current.data == data){Console.WriteLine("找到了目标"+data);return true;}current = current.next;}Console.WriteLine("没有目标" + data);return false;}

        关于改就是查的子集 只需要加一两行代码即可 所以不做演示

遍历

可以双向遍历链表哦

 #region 遍历打印/// <summary>/// 正向打印链表:按顺序输出链表中每个节点的数据/// </summary>public void PrintListForward(){// 从链表头节点开始遍历Node current = headNode;while (current != null){// 输出当前节点的数据Console.Write(current.data + " ");// 移动到下一个节点current = current.next;}Console.WriteLine();}/// <summary>/// 反向打印链表:按逆序输出链表中每个节点的数据/// </summary>public void PrintListBackward(){// 从链表尾节点开始遍历Node current = tailNode;while (current != null){// 输出当前节点的数据Console.Write(current.data + " ");// 移动到前一个节点current = current.prev;}Console.WriteLine();}

全部代码

using System;public class Node
{public int data;public Node prev;public Node next;public Node(int data, Node prev = null, Node next = null){this.data = data;this.prev = prev;this.next = next;}
}public class DoublyLinkedList
{public Node headNode;public Node tailNode;public DoublyLinkedList(){headNode = tailNode = null;}#region 增/// <summary>/// 头插法/// </summary>public void HeadAdd(int data){//如果链表为空if (headNode == null){headNode = tailNode = new Node(data);}else{//双向链表的特殊性: 修改头节点时,需要把新节点的前项 后项 都挂上Node newNode = new Node(data, null, headNode);headNode.prev = newNode;//改变链表头headNode = newNode;}}public void TailAdd(int data){//如果尾巴为空 说明头也没有 所以下面判断头尾都可以if (headNode == null){//if (tailNode ==null)headNode = tailNode = new Node(data);}else{//双向链表的特殊性: 修改尾节点时,需要把新节点的前项 后项 都挂上Node newNode = new Node(data, tailNode, null);tailNode.next = newNode;//改变链表尾tailNode = newNode;}}#endregion#region 删public void DeleteValue(int data){if (headNode == null) return;Node current = headNode;while (current != null){if (current.data == data){//如果匹配到了则可能出现以下情况://1 删除的是头节点if (current.prev == null){headNode = current.next;if (headNode != null){headNode.prev = null;}else{tailNode = null;}}//2.删除的是尾巴else if (current.next == null){tailNode = current.prev;tailNode.next = null;}//3.删除的是中间节点else{current.prev.next = current.next;current.next.prev = current.prev;}return;}current = current.next;}}#endregion#region 查询public bool SearchValue(int data){if (headNode == null) return false;Node current = headNode;while (current != null){if (current.data == data){Console.WriteLine("找到了目标" + data);return true;}current = current.next;}Console.WriteLine("没有目标" + data);return false;}#endregion#region 遍历打印/// <summary>/// 正向打印链表:按顺序输出链表中每个节点的数据/// </summary>public void PrintListForward(){// 从链表头节点开始遍历Node current = headNode;while (current != null){// 输出当前节点的数据Console.Write(current.data + " ");// 移动到下一个节点current = current.next;}Console.WriteLine();}/// <summary>/// 反向打印链表:按逆序输出链表中每个节点的数据/// </summary>public void PrintListBackward(){// 从链表尾节点开始遍历Node current = tailNode;while (current != null){// 输出当前节点的数据Console.Write(current.data + " ");// 移动到前一个节点current = current.prev;}Console.WriteLine();}#endregion
}

3.循环双向链表

        循环链表就是将头节点的前项和尾节点的后项连到同一个节点

        简称:貂蝉在一起了 噗噗

  headNode.prev = newNode;tailNode.next = newNode;

节点类

并没有什么区别

public class Node
{public int data;public Node prev;public Node next;public Node(int data){this.data = data;this.prev = null;this.next = null;}
}

链表类

也没有什么区别

public class DoublyCircularLinkedList
{public Node headNode;public Node tailNode;public DoublyCircularLinkedList(){headNode = tailNode = null;}

头插

只是将头节点的前项 和 尾节点的后项 连接在了一起

   /// <summary>/// 头插法/// </summary>public void HeadAdd(int data){Node newNode = new Node(data);if (headNode == null){headNode = tailNode = newNode;newNode.next = newNode;newNode.prev = newNode;}else{newNode.next = headNode;newNode.prev = tailNode;headNode.prev = newNode;tailNode.next = newNode;headNode = newNode;}}

尾插

    public void TailAdd(int data){Node newNode = new Node(data);if (tailNode == null){headNode = tailNode = newNode;newNode.next = newNode;newNode.prev = newNode;}else{newNode.next = headNode;newNode.prev = tailNode;tailNode.next = newNode;headNode.prev = newNode;tailNode = newNode;}}

    public void DeleteValue(int data){if (headNode == null) return;Node current = headNode;do{if (current.data == data){if (current.next == current){headNode = tailNode = null;}else{if (current == headNode){headNode = current.next;}if (current == tailNode){tailNode = current.prev;}current.prev.next = current.next;current.next.prev = current.prev;}return;}current = current.next;} while (current != headNode);}

    public bool SearchValue(int data){if (headNode == null) return false;Node current = headNode;do{if (current.data == data){Console.WriteLine("找到了目标" + data);return true;}current = current.next;} while (current != headNode);Console.WriteLine("没有目标" + data);return false;}

遍历

    #region 遍历打印/// <summary>/// 打印链表:按顺序输出链表中每个节点的数据/// </summary>public void PrintList(){if (headNode == null) return;Node current = headNode;do{Console.Write(current.data + " ");current = current.next;} while (current != headNode);Console.WriteLine();}#endregion

全部代码

public class Node
{public int data;public Node prev;public Node next;public Node(int data){this.data = data;this.prev = null;this.next = null;}
}public class DoublyCircularLinkedList
{public Node headNode;public Node tailNode;public DoublyCircularLinkedList(){headNode = tailNode = null;}#region 增/// <summary>/// 头插法/// </summary>public void HeadAdd(int data){Node newNode = new Node(data);if (headNode == null){headNode = tailNode = newNode;newNode.next = newNode;newNode.prev = newNode;}else{newNode.next = headNode;newNode.prev = tailNode;headNode.prev = newNode;tailNode.next = newNode;headNode = newNode;}}public void TailAdd(int data){Node newNode = new Node(data);if (tailNode == null){headNode = tailNode = newNode;newNode.next = newNode;newNode.prev = newNode;}else{newNode.next = headNode;newNode.prev = tailNode;tailNode.next = newNode;headNode.prev = newNode;tailNode = newNode;}}#endregion#region 删public void DeleteValue(int data){if (headNode == null) return;Node current = headNode;do{if (current.data == data){if (current.next == current){headNode = tailNode = null;}else{if (current == headNode){headNode = current.next;}if (current == tailNode){tailNode = current.prev;}current.prev.next = current.next;current.next.prev = current.prev;}return;}current = current.next;} while (current != headNode);}#endregion#region 查询public bool SearchValue(int data){if (headNode == null) return false;Node current = headNode;do{if (current.data == data){Console.WriteLine("找到了目标" + data);return true;}current = current.next;} while (current != headNode);Console.WriteLine("没有目标" + data);return false;}#endregion#region 遍历打印/// <summary>/// 打印链表:按顺序输出链表中每个节点的数据/// </summary>public void PrintList(){if (headNode == null) return;Node current = headNode;do{Console.Write(current.data + " ");current = current.next;} while (current != headNode);Console.WriteLine();}#endregion
}

 

 

相关文章:

c# 数据结构 链表篇 有关双向链表的一切

本人能力有限,如有不足还请斧正 目录 0.双向链表的好处 1.双向链表的分类 2.不带头节点的标准双向链表 节点类:有头有尾 链表类:也可以有头有尾 也可以只有头 增 头插 尾插 删 查 改 遍历 全部代码 3.循环双向链表 节点类 链表类 增 头插 尾插 删 查 遍历…...

Debian服务器挂载外部存储设备的完整指南

在 Debian 系统中挂载外部存储设备(如 U 盘、移动硬盘、SSD)是服务器运维和桌面使用中非常常见的操作。本文将为你详细拆解从识别设备、格式化到手动/自动挂载的全过程&#xff0c;适合新手到进阶用户参考。 一、准备阶段&#xff1a;插入存储设备并识别 1. 插入外部设备后查看…...

660 中值定理

文章目录 前言168169170总结 前言 background music: 《代替》 张叶蕾 660 上面没有专门的中值定理章节&#xff0c;我蒙了。不过应该可以找一下。就是证明题&#xff0c;标志性应该还行。找一下。然后做一下。660 的题质量应该还是非常高的。但是积分中值定理&#xff0c;还有…...

Elasticsearch:AI 助理 - 从通才到专才

作者&#xff1a;来自 Elastic Thorben Jndling 在 AI 世界中&#xff0c;关于构建针对特定领域定制的大型语言模型&#xff08;large language models - LLM&#xff09;的话题备受关注 —— 不论是为了更好的安全性、上下文理解、专业能力&#xff0c;还是更高的准确率。这个…...

数据结构——布隆过滤器

目录 一、什么是布隆过滤器&#xff1f; 二、布隆过滤器的原理 三、布隆过滤器的特点 一、什么是布隆过滤器&#xff1f; 布隆过滤器是一种空间效率高、适合快速检索的数据结构&#xff0c;用于判断一个元素是否可能存在于一个集合中。它通过使用多个哈希函数和一个位数组来…...

时间的重构:科技如何重塑人类的时间感知与存在方式

时间是人类认知的基石&#xff0c;也是科技发展的终极命题。从石英钟到量子计时器&#xff0c;从日晷到区块链时间戳&#xff0c;技术不断重构着我们对时间的理解与利用。然而&#xff0c;当人工智能、量子计算和脑机接口等前沿技术开始挑战时间的线性本质时&#xff0c;我们不…...

悄悄话识别、 打电话识别、攀高识别三种识别算法

在摄像头正对场景下,悄悄话识别(唇语识别)、打电话识别和攀高识别是三种典型的行为检测技术。以下从技术原理、算法模型、应用场景及挑战等方面进行详细分析: 一、悄悄话识别(唇语识别) 技术原理 唇语识别通过分析嘴唇的几何特征(形状、开合程度、运动轨迹)和动态变化…...

docker多架构镜像构建

docker多架构镜像构建 Docker 多架构镜像构建&#xff08;Multi-Architecture Image Build&#xff09;允许你为不同平台&#xff08;如 linux/amd64, linux/arm64, linux/arm/v7 等&#xff09;构建和推送统一的镜像标签&#xff0c;解决在不同硬件架构之间部署的问题。 Doc…...

机器学习常用算法总结

1. 概述 机器学习的定义是对于某类任务T和性能度量P&#xff0c;如果一个计算机程序在T上其性能P随着经验E而自我完善&#xff0c;那么我们就称这个系统从经验E中学习&#xff0c;机器学习是人工智能的一种方法&#xff0c;它通过在大量数据中学习隐藏的规则&#xff0c;模式和…...

软件架构设计:MVC、MVP、MVVM、RIA 四大风格优劣剖析

MVC、MVP、MVVM 和 RIA 都是软件架构中常见的设计风格&#xff0c;以下是对它们的详细介绍&#xff1a; 一、MVC 架构风格&#xff08;Model - View - Controller&#xff09; 1.简介&#xff1a;MVC 架构风格将软件应用程序分为三个核心部分&#xff0c;通过这种划分来分离不…...

Android12 自定义系统服务

在Android中可以通过两种方式创建系统服务: 由SystemServer启动的系统服务,使用SystemServer线程资源,适合轻量级的服务,比如各种XMS服务;占用独立进程,在系统启动时,由init进程拉起,比如SurfaceFlinger;本文采用的是第一种方式。 自定义AssistantManagerService 参…...

Flink SQL SavePoint最佳实践

以下是 Flink SQL Savepoint 最佳实践&#xff0c;涵盖配置、触发、恢复及注意事项&#xff0c;高效管理作业状态&#xff1a; 一、Savepoint 的配置与触发 1. 基础配置 存储路径&#xff1a;在 flink-conf.yaml 中全局设置 Savepoint 存储目录&#xff0c;避免每次手动指定路…...

【STM32】在FreeRTOS下使用硬件SPI收发数据出现的时序耦合问题(WK2124芯片为例)

问题 STM32中在Freertos使用SPI通讯芯片 WK2124进行SPI转4串口时&#xff0c;接收数据为一个任务&#xff0c;发送数据为一个任务&#xff0c;切接受任务优先级更高实测发现收发一段时间&#xff08;约几分钟&#xff09;外扩芯片会死锁导致WK2124复位。 分析 首先&#xff…...

关于香橙派OrangePi 5 Ultra 这个开源板子,开发Android

我下载了它资料中的开源Android13 系统SDK&#xff0c; 这个SDK连个git 都没有&#xff0c;把这种代码释放能称为开源吗&#xff1f;&#xff1f; 并且也就是说你买了这个板子&#xff0c;里面是没有任何关于RK3588的开发文档&#xff0c;如果你没玩过其他RK平台&#xff0c;估…...

ubuntu启动 Google Chrome 时默认使用中文界面,设置一个永久的启动方式

方法 &#xff1a;通过桌面快捷方式设置 编辑 Chrome 的桌面快捷方式&#xff1a; 找到您的 Google Chrome 快捷方式文件。如果是通过菜单启动&#xff0c;通常会在以下路径找到与 Chrome 相关的 .desktop 文件&#xff1a; sudo vim /usr/share/applications/google-chrome.d…...

字节跳动开源 Godel-Rescheduler:适用于云原生系统的全局最优重调度框架

背景 在云原生调度中&#xff0c;一次调度往往无法解决所有问题&#xff0c;需要配合重调度来优化资源分配和任务摆放。传统的重调度框架主要集中在识别异常节点或任务&#xff0c;并通过迁移或删除来解决。然而&#xff0c;这些框架往往只能解决局部问题&#xff0c;无法提供…...

WINUI——Background小结

在 ​​WinUI/UWP XAML​​ 中&#xff0c;Background&#xff08;或其他颜色属性&#xff09;支持 ​​多种颜色表示方式​​&#xff0c;包括以下三种主流格式&#xff1a; ​​1. RGB 十六进制&#xff08;不透明&#xff09;​​ ​​格式​​&#xff1a;#RRGGBB​​特点…...

Oracle数据库数据编程SQL<01. 课外关注:数据库查重方法全面详解>

查重是数据库管理和数据分析中的常见需求&#xff0c;以下是各种查重方法的全面总结&#xff0c;涵盖不同场景和技术手段。 更多Oracle学习内容请查看&#xff1a;Oracle保姆级超详细系列教程_Tyler先森的博客-CSDN博客 目录 一、基础SQL查重方法 1. 使用GROUP BY和HAVING …...

开源技术如何助力中小企业实现财务管理自主化?

中小企业的数字化困境与开源机遇 国际数据公司&#xff08;IDC&#xff09;研究显示&#xff0c;全球67%的中小企业因高昂的软件成本和僵化的功能设计&#xff0c;未能有效推进数字化转型。传统商业软件常面临三大矛盾&#xff1a; 功能冗余与核心需求缺失&#xff1a;标准化系…...

边缘计算与隐私计算的融合:构建数据经济的“隐形护盾“

在数据成为核心生产要素的今天&#xff0c;边缘计算与隐私计算的交汇正在重塑技术生态。这并非简单的技术叠加&#xff0c;而是一场关于数据主权、算力分配与信任机制的深度博弈。本文将从"数据流动的拓扑学"视角&#xff0c;探讨二者融合如何重构数字社会的基础设施…...

【大模型实战篇】--阿里云百炼搭建MCP Agent

MCP协议&#xff08;Model Communication Protocol&#xff0c;模型通信协议&#xff09;是大语言模型&#xff08;LLM&#xff09;与外部系统或其他模型交互时的一种标准化通信框架&#xff0c;旨在提升交互效率、安全性和可扩展性。 目录 1.阿里云百炼--MCP 1.1.MCP 服务接…...

基于PySide6与pycatia的CATIA智能倒角工具开发全解析

引言&#xff1a;工业设计中的倒角革命 在机械设计领域&#xff0c;倒角操作是零件加工前的必要工序。传统手动操作效率低下且易出错本文基于PySide6pycatia技术栈&#xff0c;提出一种支持批量智能倒角、参数动态校验、跨层级操作的自动化方案&#xff0c;其核心突破体现在&a…...

css 二维码始终显示在按钮的正下方,并且根据不同的屏幕分辨率自动调整位置

一、需求 “求职入口” 下面的浮窗位置在其正下方&#xff0c;并且浏览器分辨的改变&#xff08;拖动浏览器&#xff09;&#xff0c;位置依旧在最下方 二、实现 <div class"btn_box"><div class"btn_link id"js-apply">求职入口<di…...

串口接收的使用-中断

1、引言 单片机串口、按键等等这种外部输入的&#xff0c; 用轮询的方式非常浪费资源&#xff0c;所以最好的方法就是使用中断接收数据。 2、串口 对于串口中断&#xff0c; 使用的非常频繁。 1. 基本原理 串口中断接收通过以下方式工作&#xff1a; 当串口接收到一个字节…...

处理 Flutter 没有反应

现象 有以下几种 VS Code 中 Initializing the Flutter SDK. This may take a few minutes. 会一直维持在这个右下角提示窗, 但是无后续动作 Flutter CMD flutter_console.bat 执行 --version 或者 doctor [-v] 没有任何输出, 命令卡住 解决办法 参考官方说明 管理员身份…...

Linux-服务器负载评估方法

在 Linux 服务器中&#xff0c;top 命令显示的 load average&#xff08;平均负载&#xff09;反映了系统在特定时间段内的负载情况。它通常显示为三个数值&#xff0c;分别代表过去 1 分钟、5 分钟和 15 分钟的平均负载。 1. 什么是 Load Average&#xff1f; Load average …...

入门51单片机(1)-----点灯大师梦开始的地方

前言 这一次的博客主要是要记录一下学习的记录的,方便以后去复习一下的&#xff0c;当然这篇博客还是针于零基础的伙伴萌&#xff0c;看完这篇博客&#xff0c;大家就可以学会点灯了。 安装软件 方法一下一下来教&#xff01;&#xff01;萌新宝贝萌可以学会的&#xff01;帮…...

3.数组(随想录)

1.二分查找 *2.移除元素 还有一个小优化&#xff08;可以不看&#xff09; 3.有序数组的平方 *4.长度最小的子数组 &#xff08;3种解法&#xff09; 5.螺旋矩阵 ||...

解决import pyqtgraph.opengl报错

在使用pyqtgraph时&#xff0c;出现没有OpenGL模块的报错 报错信息 ModuleNotFoundError: No module named OpenGL 解决方案 该环境下没有安装OpenGL库导致&#xff0c;输入以下代码进行安装&#xff1a; pip install PyOpenGL conda install -c conda-forge pyopengl 安…...

大模型面经 | 请你介绍一下ReAct(Reasoning and Acting)?

大家好,我是皮先生!! 今天给大家分享一些关于大模型面试常见的面试题,希望对大家的面试有所帮助。 往期回顾: 大模型面经 | 春招、秋招算法面试常考八股文附答案(RAG专题一) 大模型面经 | 春招、秋招算法面试常考八股文附答案(RAG专题二) 大模型面经 | 春招、秋招算法…...