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

Java基础系列-LinkedList源码解析

文章目录

  • 简介
    • LinkedList 插入和删除元素的时间复杂度?
    • LinkedList 为什么不能实现 RandomAccess 接口?
  • LinkedList 源码分析
    • Node 定义
    • 初始化
    • 获取元素
    • 插入元素
    • 删除元素
    • 遍历链表

简介

LinkedList 是一个基于双向链表实现的集合类,经常被拿来和 ArrayList 做比较。
在这里插入图片描述

不过,我们在项目中一般是不会使用到 LinkedList 的,需要用到 LinkedList 的场景几乎都可以使用 ArrayList 来代替,并且,性能通常会更好!就连 LinkedList 的作者约书亚 · 布洛克(Josh Bloch)自己都说从来不会使用 LinkedList

另外,不要下意识地认为 LinkedList 作为链表就最适合元素增删的场景。LinkedList 仅仅在头尾插入或者删除元素的时候时间复杂度近似 O(1),其他情况增删元素的平均时间复杂度都是 O(n) 。

LinkedList 插入和删除元素的时间复杂度?

  • 头部插入/删除:只需要修改头结点的指针即可完成插入/删除操作,因此时间复杂度为 O(1)。

  • 尾部插入/删除:只需要修改尾结点的指针即可完成插入/删除操作,因此时间复杂度为 O(1)。

  • 指定位置插入/删除:需要先移动到指定位置,再修改指定节点的指针完成插入/删除,不过由于有头尾指针,可以从较近的指针出发,因此需要遍历平均 n/4 个元素,时间复杂度为 O(n)。

LinkedList 为什么不能实现 RandomAccess 接口?

RandomAccess 是一个标记接口,用来表明实现该接口的类支持随机访问(即可以通过索引快速访问元素)。由于 LinkedList 底层数据结构是链表,内存地址不连续,只能通过指针来定位,不支持随机快速访问,所以不能实现 RandomAccess 接口。

LinkedList 源码分析

Node 定义

LinkedList 中的元素是通过 Node 定义的:

private static class Node<E> {E item;// 节点值Node<E> next; // 指向的下一个节点(后继节点)Node<E> prev; // 指向的前一个节点(前驱结点)// 初始化参数顺序分别是:前驱结点、本身节点值、后继节点Node(Node<E> prev, E element, Node<E> next) {this.item = element;this.next = next;this.prev = prev;}
}

初始化

LinkedList 中有一个无参构造函数和一个有参构造函数。

// 创建一个空的链表对象
public LinkedList() {
}// 接收一个集合类型作为参数,会创建一个与传入集合相同元素的链表对象
public LinkedList(Collection<? extends E> c) {this();addAll(c);
}

获取元素

LinkedList获取元素相关的方法一共有 3 个:

  1. getFirst():获取链表的第一个元素。

  2. getLast():获取链表的最后一个元素。

  3. get(int index):获取链表指定位置的元素。

// 获取链表的第一个元素
public E getFirst() {final Node<E> f = first;if (f == null)throw new NoSuchElementException();return f.item;
}// 获取链表的最后一个元素
public E getLast() {final Node<E> l = last;if (l == null)throw new NoSuchElementException();return l.item;
}// 获取链表指定位置的元素
public E get(int index) {// 下标越界检查,如果越界就抛异常checkElementIndex(index);// 返回链表中对应下标的元素return node(index).item;
}

这里的核心在于 node(int index) 这个方法:

// 返回指定下标的非空节点
Node<E> node(int index) {// 断言下标未越界// assert isElementIndex(index);// 如果index小于size的二分之一  从前开始查找(向后查找)  反之向前查找if (index < (size >> 1)) {Node<E> x = first;// 遍历,循环向后查找,直至 i == indexfor (int i = 0; i < index; i++)x = x.next;return x;} else {Node<E> x = last;for (int i = size - 1; i > index; i--)x = x.prev;return x;}
}

get(int index)remove(int index) 等方法内部都调用了该方法来获取对应的节点。

从这个方法的源码可以看出,该方法通过比较索引值与链表 size 的一半大小来确定从链表头还是尾开始遍历。如果索引值小于 size 的一半,就从链表头开始遍历,反之从链表尾开始遍历。这样可以在较短的时间内找到目标节点,充分利用了双向链表的特性来提高效率。

插入元素

在这里插入图片描述

add() 方法有两个版本:

  • add(E e):用于在 LinkedList 的尾部插入元素,即将新元素作为链表的最后一个元素,时间复杂度为 O(1)。

  • add(int index, E element):用于在指定位置插入元素。这种插入方式需要先移动到指定位置,再修改指定节点的指针完成插入/删除,因此需要移动平均 n/4 个元素,时间复杂度为 O(n)

// 在链表尾部插入元素
public boolean add(E e) {linkLast(e);return true;
}// 在链表指定位置插入元素
public void add(int index, E element) {// 下标越界检查checkPositionIndex(index);// 判断 index 是不是链表尾部位置if (index == size)// 如果是就直接调用 linkLast 方法将元素节点插入链表尾部即可linkLast(element);else// 如果不是则调用 linkBefore 方法将其插入指定元素之前linkBefore(element, node(index));
}// 将元素节点插入到链表尾部
void linkLast(E e) {// 将最后一个元素赋值(引用传递)给节点 lfinal Node<E> l = last;// 创建节点,并指定节点前驱为链表尾节点 last,后继引用为空final Node<E> newNode = new Node<>(l, e, null);// 将 last 引用指向新节点last = newNode;// 判断尾节点是否为空// 如果 l 是null 意味着这是第一次添加元素if (l == null)// 如果是第一次添加,将first赋值为新节点,此时链表只有一个元素first = newNode;else// 如果不是第一次添加,将新节点赋值给l(添加前的最后一个元素)的nextl.next = newNode;size++;modCount++;
}// 在指定元素之前插入元素
void linkBefore(E e, Node<E> succ) {// assert succ != null;断言 succ不为 null// 定义一个节点元素保存 succ 的 prev 引用,也就是它的前一节点信息final Node<E> pred = succ.prev;// 初始化节点,并指明前驱和后继节点final Node<E> newNode = new Node<>(pred, e, succ);// 将 succ 节点前驱引用 prev 指向新节点succ.prev = newNode;// 判断前驱节点是否为空,为空表示 succ 是第一个节点if (pred == null)// 新节点成为第一个节点first = newNode;else// succ 节点前驱的后继引用指向新节点pred.next = newNode;size++;modCount++;
}

删除元素

LinkedList删除元素相关的方法一共有 5 个,可以直接看核心方法 unlink:

  1. removeFirst():删除并返回链表的第一个元素。

  2. removeLast():删除并返回链表的最后一个元素。

  3. remove(E e):删除链表中首次出现的指定元素,如果不存在该元素则返回 false。

  4. remove(int index):删除指定索引处的元素,并返回该元素的值。

  5. void clear():移除此链表中的所有元素。

// 删除并返回链表的第一个元素
public E removeFirst() {final Node<E> f = first;if (f == null)throw new NoSuchElementException();return unlinkFirst(f);
}// 删除并返回链表的最后一个元素
public E removeLast() {final Node<E> l = last;if (l == null)throw new NoSuchElementException();return unlinkLast(l);
}// 删除链表中首次出现的指定元素,如果不存在该元素则返回 false
public boolean remove(Object o) {// 如果指定元素为 null,遍历链表找到第一个为 null 的元素进行删除if (o == null) {for (Node<E> x = first; x != null; x = x.next) {if (x.item == null) {unlink(x);return true;}}} else {// 如果不为 null ,遍历链表找到要删除的节点for (Node<E> x = first; x != null; x = x.next) {if (o.equals(x.item)) {unlink(x);return true;}}}return false;
}// 删除链表指定位置的元素
public E remove(int index) {// 下标越界检查,如果越界就抛异常checkElementIndex(index);return unlink(node(index));
}

这里的核心在于 unlink(Node<E> x) 这个方法:

E unlink(Node<E> x) {// 断言 x 不为 null// assert x != null;// 获取当前节点(也就是待删除节点)的元素final E element = x.item;// 获取当前节点的下一个节点final Node<E> next = x.next;// 获取当前节点的前一个节点final Node<E> prev = x.prev;// 如果前一个节点为空,则说明当前节点是头节点if (prev == null) {// 直接让链表头指向当前节点的下一个节点first = next;} else { // 如果前一个节点不为空// 将前一个节点的 next 指针指向当前节点的下一个节点prev.next = next;// 将当前节点的 prev 指针置为 null,,方便 GC 回收x.prev = null;}// 如果下一个节点为空,则说明当前节点是尾节点if (next == null) {// 直接让链表尾指向当前节点的前一个节点last = prev;} else { // 如果下一个节点不为空// 将下一个节点的 prev 指针指向当前节点的前一个节点next.prev = prev;// 将当前节点的 next 指针置为 null,方便 GC 回收x.next = null;}// 将当前节点元素置为 null,方便 GC 回收x.item = null;size--;modCount++;return element;
}

unlink() 方法的逻辑如下:

  1. 首先获取待删除节点 x 的前驱和后继节点;

  2. 判断待删除节点是否为头节点或尾节点:

    • 如果 x 是头节点,则将 first 指向 x 的后继节点 next

    • 如果 x 是尾节点,则将 last 指向 x 的前驱节点 prev

    • 如果 x 不是头节点也不是尾节点,执行下一步操作

  3. 将待删除节点 x 的前驱的后继指向待删除节点的后继 next,断开 x 和 x.prev 之间的链接;

  4. 将待删除节点 x 的后继的前驱指向待删除节点的前驱 prev,断开 x 和 x.next 之间的链接;

  5. 将待删除节点 x 的元素置空,修改链表长度。

在这里插入图片描述

遍历链表

推荐使用for-each 循环来遍历 LinkedList 中的元素, for-each 循环最终会转换成迭代器形式。

LinkedList<String> list = new LinkedList<>();
list.add("apple");
list.add("banana");
list.add("pear");for (String fruit : list) {System.out.println(fruit);
}

LinkedList 的遍历的核心就是它的迭代器的实现。

// 双向迭代器
private class ListItr implements ListIterator<E> {// 表示上一次调用 next() 或 previous() 方法时经过的节点;private Node<E> lastReturned;// 表示下一个要遍历的节点;private Node<E> next;// 表示下一个要遍历的节点的下标,也就是当前节点的后继节点的下标;private int nextIndex;// 表示当前遍历期望的修改计数值,用于和 LinkedList 的 modCount 比较,判断链表是否被其他线程修改过。private int expectedModCount = modCount;…………
}

下面我们对迭代器 ListItr 中的核心方法进行详细介绍。

我们先来看下从头到尾方向的迭代:

// 判断还有没有下一个节点
public boolean hasNext() {// 判断下一个节点的下标是否小于链表的大小,如果是则表示还有下一个元素可以遍历return nextIndex < size;
}
// 获取下一个节点
public E next() {// 检查在迭代过程中链表是否被修改过checkForComodification();// 判断是否还有下一个节点可以遍历,如果没有则抛出 NoSuchElementException 异常if (!hasNext())throw new NoSuchElementException();// 将 lastReturned 指向当前节点lastReturned = next;// 将 next 指向下一个节点next = next.next;nextIndex++;return lastReturned.item;
}

再来看一下从尾到头方向的迭代:

// 判断是否还有前一个节点
public boolean hasPrevious() {return nextIndex > 0;
}// 获取前一个节点
public E previous() {// 检查是否在迭代过程中链表被修改checkForComodification();// 如果没有前一个节点,则抛出异常if (!hasPrevious())throw new NoSuchElementException();// 将 lastReturned 和 next 指针指向上一个节点lastReturned = next = (next == null) ? last : next.prev;nextIndex--;return lastReturned.item;
}

如果需要删除或插入元素,也可以使用迭代器进行操作。

LinkedList<String> list = new LinkedList<>();
list.add("apple");
list.add(null);
list.add("banana");//  Collection 接口的 removeIf 方法底层依然是基于迭代器
list.removeIf(Objects::isNull);for (String fruit : list) {System.out.println(fruit);
}

迭代器对应的移除元素的方法如下:

// 从列表中删除上次被返回的元素
public void remove() {// 检查是否在迭代过程中链表被修改checkForComodification();// 如果上次返回的节点为空,则抛出异常if (lastReturned == null)throw new IllegalStateException();// 获取当前节点的下一个节点Node<E> lastNext = lastReturned.next;// 从链表中删除上次返回的节点unlink(lastReturned);// 修改指针if (next == lastReturned)next = lastNext;elsenextIndex--;// 将上次返回的节点引用置为 null,方便 GC 回收lastReturned = null;expectedModCount++;
}

相关文章:

Java基础系列-LinkedList源码解析

文章目录 简介LinkedList 插入和删除元素的时间复杂度&#xff1f;LinkedList 为什么不能实现 RandomAccess 接口&#xff1f; LinkedList 源码分析Node 定义初始化获取元素插入元素删除元素遍历链表 简介 LinkedList 是一个基于双向链表实现的集合类&#xff0c;经常被拿来和…...

pycharm无法识别到本地python的conda环境解决方法

问题一 现象描述&#xff1a; 本地已经安装了conda&#xff0c;但在pycharm中选择conda环境却识别不到&#xff0c; 解决方法&#xff1a;手动输入conda path&#xff0c;点击R eload environments基本就能修复&#xff0c;比如我的路径如下 /Users/test/conda/miniconda3/b…...

【机器人创新创业应需明确产品定位与方向指南】

机器人领域的创新创业, 需要对公司和产品的定位和生态进行深入思考, 明确其定位与发展目标, 明确产品在是为G、为B还是为C进行服务。 本文引用地址&#xff1a;https://www.eepw.com.cn/article/202504/469401.htm 超前的、探索性的创新技术一般是面向G端, 而不是面向B端或者C…...

《似锦》:画饼之—你画给我我画给你

甄珩&#xff0c;看似刚正不阿&#xff0c;正得发邪&#xff0c;一板一眼的严肃角色 可是每次余七和甄珩在一起&#xff0c;就是一部行走的喜剧&#xff0c;众网友称他们为“甄儿八锦” 《似锦》剧集精彩片段&#xff1a;甄珩余七爆笑修罗场&#xff08;四&#xff09; 谁懂这…...

鸿蒙系统开发中路由使用详解

鸿蒙系统提供了两种主要的路由机制&#xff1a;传统的Router模块和组件化的Navigation容器。下面我将详细介绍这两种路由方式的使用方法、区别以及实际应用示例。 一、Router模块基础使用 Router是鸿蒙早期提供的页面路由模块&#xff0c;通过URL实现页面跳转和数据传递。 1…...

拖拉拽效果加点击事件

<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><title>自由拖拽点击元素</title><style>body {margin: 0;height: 100vh;display: flex;justify-content: center;align-items: center;backgr…...

Ubuntu利用docker搭建Java相关环境记录(二)

Ubuntu利用docker搭建Java相关环境记录&#xff08;二&#xff09; 接上篇&#xff1a;Ubuntu利用docker搭建Java相关环境记录&#xff08;一&#xff09; 启动Docker 1. 查看Docker容器 已启动的容器 docker ps所有容器 docker ps -a本人很懒并不想一直敲命令操作&#…...

2025华中杯B题——AI实现

以下内容全文由以下网站AI实现&#xff0c;内容和代码仅供参考 如需实现自己的需求和目标&#xff0c;请使用网站自行调试。 参考写作 1. 共享单车数量与分布估算 问题分析 本题要求根据校园共享单车在各停车点的不同时段统计数据&#xff0c;估算校园内共享单车总量&#…...

【软考-系统架构设计师】OSI体系解析

一、OSI体系的核心定义 OSI&#xff08;Open System Interconnection&#xff09;模型是国际标准化组织&#xff08;ISO&#xff09;于1984年提出的网络通信分层框架&#xff0c;旨在解决异构网络系统间的兼容性问题。它将复杂的网络通信过程划分为七层&#xff0c;每层独立完…...

用手机也能打《无畏契约》?登录ToDesk即可开玩

《无畏契约》火到出圈&#xff01;但手机玩家只能干瞪眼&#xff1f; 作为拳头游戏继《英雄联盟》后的又一爆款&#xff0c;《无畏契约》凭借快节奏的战术对抗和全球化的地图设计&#xff08;比如东京“霓虹町”、百慕大“微风岛屿”&#xff09;&#xff0c;迅速成为电竞圈的顶…...

jmeter提取返回值到文件

前言 如何将请求的返回值&#xff0c;保存到本地文件&#xff0c;有具体以下3种方式。 保存到响应文件BeanShell 取样器BeanShell 后置处理程序 一、监听器–保存响应到文件 1、提取全部返回值&#xff0c;&#xff08;.json&#xff09;格式 2、保存到响应文件 添加----…...

iPaaS集成平台在电商行业的五大核心应用场景

在电商行业“多平台运营、多系统并行”的竞争格局下&#xff0c;订单激增、数据割裂、跨系统协作低效等问题成为企业增长的隐形阻碍。谷云科技作为国内领先的iPaaS&#xff08;集成平台即服务&#xff09;技术厂商&#xff0c;通过低代码、高扩展的集成能力&#xff0c;帮助电商…...

猪行为视频数据集

猪行为数据集包含 23 天(超过 6 周)的日间猪行为视频,这些视频由近乎架空的摄像机拍摄。视频已配准颜色和深度信息。数据以每秒 6 帧的速度捕获,并以 1800 帧(5 分钟)为一批次进行存储。大多数帧显示 8 头猪。 这里可以看到颜色和深度图像的示例: 喂食器位于图片底部中…...

在conda环境下使用pip安装库无法import

安装seleniumwire包&#xff0c;conda环境没有&#xff0c;pip之后安装不到当前conda环境 网上的方法都试过了&#xff0c;包括强制安装等 python -m pip install --upgrade --force-reinstall selenium-wire 最后定位应该是没有安装到当前conda的环境下&#xff0c;使用list…...

[net 6] udp_chat_server基于udp的简单聊天室(多线程的服务器与业务相分离)

目录 1. 网络聊天室的意义 2. 网络聊天室了解 2.1. 网络聊天室模块分析 2.2. 目标 3. 基本框架 3.1. 文件基本框架 3.2. 设计回调函数解耦 4. Route.hpp 模块(消息转发) 4.1. 头文件包含 4.2. 基本类框架 4.3. Route::Forward() 转发 4.3.1. 函数头设计 4.3.2. 维护…...

驱动-自旋锁

前面原子操作进行了讲解&#xff0c; 并使用原子整形操作对并发与竞争实验进行了改进&#xff0c;但是原子操作只能对整形变量或者位进行保护&#xff0c; 而对于结构体或者其他类型的共享资源&#xff0c; 原子操作就力不从心了&#xff0c; 这时候就轮到自旋锁的出场了。 两个…...

TDengine 存储引擎剖析:数据文件与索引设计(二)

TDengine 索引设计 索引设计关键特性 TDengine 的索引设计采用了多种技术和策略&#xff0c;以满足时序数据高效存储和快速查询的需求&#xff0c;具有以下关键特性&#xff1a; 多级时间戳压缩索引&#xff1a;TDengine 使用了时间戳压缩索引技术&#xff0c;能够有效减少索…...

基于Python的医疗质量管理指标智能提取系统【2025代码版】

系统概述 本系统旨在帮助医疗质量管理部从医院信息系统(HIS)中智能提取《2025年国家医疗质量安全改进目标》中的关键指标数据。系统采用Python编程语言,结合现代数据处理库,实现高效、准确的数据提取与分析功能。 import json import logging import logging.handlers impo…...

中介者模式(Mediator Pattern)

中介者模式(Mediator Pattern)是一种行为型设计模式。它通过引入一个中介者对象,来封装一系列对象之间的交互,使这些对象之间不再直接相互引用和通信,而是通过中介者进行间接通信,从而降低对象之间的耦合度,提高系统的可维护性和可扩展性。 一、基础 1. 意图 核心目的…...

Hbuilder 上的水印相机实现方案 (vue3 + vite + hbuilder)

效果 思路 通过 live-pusher 这个视频推流的组件来获取摄像头拿到视频的一帧图片之后&#xff0c;跳转到正常的 vue 页面&#xff0c;通过 canvas 来处理图片水印 源码 live-pusher 这个组件必须是 nvue 的 至于什么是 nvue&#xff0c;看这个官方文档吧 https://uniapp.dcl…...

聊聊Spring AI Alibaba的PdfTablesParser

序 本文主要研究一下Spring AI Alibaba的PdfTablesParser PdfTablesParser community/document-parsers/spring-ai-alibaba-starter-document-parser-pdf-tables/src/main/java/com/alibaba/cloud/ai/parser/pdf/tables/PdfTablesParser.java public class PdfTablesParser…...

二分查找-LeetCode

题目 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target&#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 示例 1: 输入: nums [-1,0,3,5,9,12], target 9 输出: 4 解释: …...

StarRocks Community Monthly Newsletter (Mar)

版本动态 3.4.1 版本更新 核心功能升级 数据安全与权限管控 支持「安全视图」功能&#xff0c;严格管控视图查询权限 MySQL协议连接支持SSL认证&#xff0c;保障数据传输安全 存算分离架构增强 支持自动创建Snapshot&#xff08;集群恢复更便捷&#xff09; Storage Volu…...

STM32+dht11+rc522+jq8400的简单使用

1.dht11的使用 硬件&#xff1a;3v3&#xff0c;gnd&#xff0c;data数据线接一个gpio&#xff0c;三根线即可 软件&#xff1a; ①dht11.c #include "dht11.h" #include "delay.h" #include "stdbool.h"static STRUCT_DHT11_TYPEDEF dht11;…...

mpstat指令介绍

文章目录 1. 功能介绍2. 语法介绍3. 应用场景4. 实际举例 1. 功能介绍 mpstat 英文全称( Multi-Processor Statistics)&#xff0c;多处理器统计信息的含义。 下面大致说一下功能作用&#xff1a; 多核性能监控 可实时监控每个 CPU 核心的利用率、中断频率、上下文切换等指标&…...

网络层IP协议知识大梳理

全是通俗易懂的讲解&#xff0c;如果你本节之前的知识都掌握清楚&#xff0c;那就速速来看我的IP协议笔记吧~ 自己写自己的八股&#xff01;让未来的自己看懂&#xff01; &#xff08;全文手敲&#xff0c;受益良多&#xff09; 网路基础3 网路层 TCP并没有把数据发到网路…...

Linux-codec

codec原理图 codec接口 ①音频输入接口&#xff0c;连接mic ②音频输出接口&#xff0c;连接speaker ③sai/i2s接口&#xff0c;连接soc&#xff0c;soc和codec互发音频数据 ④i2c接口&#xff0c;连接soc&#xff0c;soc配置codecsai音频接口 MCLK&#xff1a;主时钟&#x…...

HTTP协议与web服务器

HTTP协议与web服务器 目录 一、浏览器与服务器通信过程 1.1 域名解析与连接建立 1.2 数据交互 1.3 连接管理 二、HTTP请求报头 2.1 请求行 2.2 请求报头 2.3 空行 2.4 请求体 三、HTTP应答报头 3.1 http应答报文头部信息 1. 状态行 2. 服务器名称 3. 数据长度 4…...

ECharts散点图-散点图7,附视频讲解与代码下载

引言&#xff1a; ECharts散点图是一种常见的数据可视化图表类型&#xff0c;它通过在二维坐标系或其它坐标系中绘制散乱的点来展示数据之间的关系。本文将详细介绍如何使用ECharts库实现一个散点图&#xff0c;包括图表效果预览、视频讲解及代码下载&#xff0c;让你轻松掌握…...

蓝桥杯之二分法(二)

存在某条件使得一边均满足&#xff0c;一边均不满足&#xff1a; 如果问题满足某种条件&#xff0c;使得在某个点之前的所有值都满足条件&#xff0c;而之后的所有值都不满足条件&#xff08;或反之&#xff09;&#xff0c;那么可以使用二分法来找到这个边界。 1.问题的解具有…...

当 AI 有了 “万能插头” 和 “通用语言”:MCP 与 A2A 如何重构智能体生态

目录 一、MCP&#xff1a;让 AI 拥有 “万能工具插头” 1.1 从 “手工对接” 到 “即插即用” 1.2 架构解密&#xff1a;AI 如何 “指挥” 工具干活 1.3 安全优势&#xff1a;数据不出门&#xff0c;操作可追溯 二、A2A&#xff1a;让智能体学会 “跨语言协作” 2.1 从 “…...

从零开始 保姆级教程 Ubuntu20.04系统安装MySQL8、服务器配置MySQL主从复制、本地navicat远程连接服务器数据库

从零开始&#xff1a;Ubuntu 20.04 系统安装 MySQL 8、服务器配置 MySQL 主从复制、本地 Navicat 远程连接服务器数据库 初始化服务器1. 更新本地软件包列表2. 安装 MySQL 服务器3. 查看 MySQL 安装版本4. 登录 MySQL 管理终端5. 设置 root 用户密码&#xff08;推荐使用 nativ…...

PHP序列化/反序列化漏洞原理

PHP反序列化原理详解 引言 PHP反序列化是PHP中一个重要的概念&#xff0c;它允许将序列化后的数据重新转换为原始的数据结构。在PHP中&#xff0c;可以使用serialize()函数将数据序列化为字符串&#xff0c;然后使用unserialize()函数将序列化后的字符串反序列化为原来的数据结…...

并查集(力扣2316)

这种涉及不同连通分量的&#xff0c;看上去就可以用并查集。并查集的模板请参见上一篇内容。并查集&#xff08;力扣1971&#xff09;-CSDN博客 现在我们要求的是无法互相到达的点对。根据观察易得&#xff0c;我们只需要求出每个并查集的元素数量&#xff0c;然后遍历每个点&…...

【web服务_负载均衡Nginx】一、Nginx 基础与核心概念解析

一、Nginx 概述&#xff1a;从起源到行业地位​ Nginx&#xff08;发音为 “engine x”&#xff09;是一款高性能的开源 Web 服务器、反向代理服务器&#xff0c;同时具备负载均衡、内容缓存、TCP/UDP 代理及邮件代理等功能。它由俄罗斯工程师伊戈尔・赛索耶夫&#xff08;Igo…...

【Python入门】文件读取全攻略:5种常用格式(csv/excel/word/ppt/pdf)一键搞定 | 附完整代码示例

大家好&#xff0c;我是唐叔&#xff01;今天给大家带来一篇Python文件读取的终极指南。无论是数据分析、办公自动化还是爬虫开发&#xff0c;文件读取都是Python程序员必须掌握的核心技能。本文将详细介绍Python处理5大常用文件格式的方法&#xff0c;包含完整可运行的代码示例…...

考研系列-计算机网络冲刺考点汇总(下)

写在前面 本文将总结王道408考研课程的计算机网络冲刺考点的第四章到第六章内容&#xff08;网络层、传输层、应用层&#xff09;。 第四章、网络层 1.SDN SDN的基本概念 注意对应关系&#xff1a;数据平面-转发&#xff1b;控制平面-路由选择 2.路由选择算法 (1)RIP协议-基于…...

GitLab-CI集成FTP自动发布

简介 在某些场景下&#xff0c;代码是以 FTP 的方式部署到服务器上&#xff0c;那么我们可以使用 GitLab-CI 来实现自动发布。 配置参考 .sftp-deploy: &sftp-deploy |-files$(git log -10 --prettyformat: --name-only | grep -v ^$ | sort -u)include_patterns$(echo …...

Ubuntu 安装cuda踩坑记录

Ubuntu 安装cuda踩坑记录&#xff1a; 运行run文件时出错&#xff1a; sh cuda_12.4.0_550.54.14_linux.run 报错&#xff1a; ./cuda-installer: error while loading shared libraries: libxml2.so.2: cannot open shared object file: No such file or directory 解决&am…...

用GitHub Actions实现CI/CD

目录 简介GitHub Actions基础工作流配置文件实战案例 Node.js应用Python应用Docker容器构建与部署 最佳实践常见问题与解决方案总结 简介 持续集成/持续部署(CI/CD)已成为现代软件开发不可或缺的一部分。它通过自动化构建、测试和部署过程&#xff0c;帮助开发团队更快、更可…...

使用AI工具打造专业级PPT的完整方案,结合 DeepSeek构思、Kimi生成内容、Napkin优化设计 等工具,分阶段详细说明流程及工具使用

以下是使用AI工具打造专业级PPT的完整方案&#xff0c;结合 DeepSeek构思、Kimi生成内容、Napkin优化设计 等工具&#xff0c;分阶段详细说明流程及工具使用&#xff1a; 一、全流程阶段划分 阶段目标核心工具1. 构思阶段明确主题、结构、核心信息&#xff0c;生成大纲与逻辑…...

【数据结构】线性表( List)和 顺序表(ArrayList)

【数据结构】线性表&#xff08; List&#xff09;和 顺序表&#xff08;ArrayList&#xff09; 一、线性表 List二、List 接口的常用方法三、ArrayList与顺序表3.1 引入顺序表的原因&#xff1f;3.2 ArrayList 的使用3.2.1 ArrayList 的创建3.2.2 添加元素&#xff1a;list.ad…...

嵌入式开发--STM32软件和硬件CRC的使用--续篇

本文是《嵌入式开发–STM32软件和硬件CRC的使用》的续篇&#xff0c;又踩到一个坑&#xff0c;发出来让大家避一下坑。 按照G0系列的设置&#xff0c;得出错误的结果 前文对应的是STM32G0系列&#xff0c;今天在用STM32G4系列时&#xff0c;按照前文的设置&#xff0c;用硬件…...

探索鸡养殖虚拟仿真实验:科技赋能养殖新体验

在科技飞速发展的今天&#xff0c;虚拟仿真技术逐渐渗透到各个领域&#xff0c;就连传统的养殖业也迎来了数字化的变革。最近&#xff0c;我参与了一场别开生面的鸡养殖虚拟仿真实验&#xff0c;不仅学到了专业的养殖知识&#xff0c;还收获了前所未有的沉浸式体验。现在&#…...

知识图谱中医知识问答系统|养生医案综合可视化系|推荐算法|vue+flask+neo4j+mysql

文章结尾部分有CSDN官方提供的学长 联系方式名片 文章结尾部分有CSDN官方提供的学长 联系方式名片 关注B站&#xff0c;有好处&#xff01; ✅编号 :F040 pro ✅技术架构: vueflaskmysqlneo4jltpac ✅实现功能&#xff1a;实现基于中医药材和药方的知识图谱可视化&#xff0c;在…...

【AI】——结合Ollama、Open WebUI和Docker本地部署可视化AI大语言模型

&#x1f3bc;个人主页&#xff1a;【Y小夜】 &#x1f60e;作者简介&#xff1a;一位双非学校的大三学生&#xff0c;编程爱好者&#xff0c; 专注于基础和实战分享&#xff0c;欢迎私信咨询&#xff01; &#x1f386;入门专栏&#xff1a;&#x1f387;【MySQL&#xff0…...

AI 模型高效化:推理加速与训练优化的技术原理与理论解析

AI 模型高效化&#xff1a;推理加速与训练优化的技术原理与理论解析 文章目录 AI 模型高效化&#xff1a;推理加速与训练优化的技术原理与理论解析一、推理加速&#xff1a;让模型跑得更快的“程序员魔法”&#xff08;一&#xff09;动态结构自适应推理&#xff1a;像人类一样…...

python学习—详解word邮件合并

系列文章目录 python学习—合并TXT文本文件 python学习—统计嵌套文件夹内的文件数量并建立索引表格 python学习—查找指定目录下的指定类型文件 python学习—年会不能停&#xff0c;游戏抽签抽奖 python学习—循环语句-控制流 python学习—合并多个Excel工作簿表格文件 pytho…...

vscode与vim+cscope+tags热键冲突

[ctrl w] s 对于vim时水平分割窗口热键 对vscode, [ctrl w]时关闭当前窗口热键 在vscode中如下配置可以发送热键到shell, 跳过vscode:...

直播系统源码开发:解锁幸运礼物功能的商业魔力与运营策略

在当今如火如荼的直播经济中&#xff0c;幸运礼物功能已成为平台提升用户黏性、刺激消费的"黄金按钮"。山东布谷科技将深入剖析幸运礼物功能的技术逻辑与商业价值&#xff0c;并为运营者提供一套完整的策略框架&#xff0c;帮助您在激烈的直播赛道中脱颖而出。 一、…...