Java基础 集合框架 队列架构 双端队列 Deque

双端队列 Deque

  • Deque 方法简介
  • Deque 核心特点
  • Deque实现类 ArrayDeque
    • ArrayDeque 构造方法
    • ArrayDeque 的数据结构及实现原理
    • ArrayDeque 方法介绍
    • ArrayDeque 核心特性
    • ArrayDeque 总结
    • ArrayDeque 使用样例代码
  • Deque实现类 LinkedList
  • Deque实现类 ConcurrentLinkedDeque (非阻塞线程安全)
    • ConcurrentLinkedDeque 核心特性
    • ConcurrentLinkedDeque 方法
    • ConcurrentLinkedDeque 数据结构和实现原理
    • ConcurrentLinkedDeque 总结
    • ConcurrentLinkedDeque 代码使用示例
  • ArrayDeque 与 LinkedList 对比
  • Deque总结

双端队列的核心特点在于 在队列的两端进行插入和删除操作,在队列的 前端Front后端Rear 高效地进行插入和删除操作。它融合了 普通队列(先进先出 - FIFO)栈(后进先出 - LIFO)的特性

public interface Deque<E> extends Queue<E> {}

Deque 方法简介

比起基本队列Deque 为每种操作(插入、移除、检查)在队列的两端(头部和尾部)都提供了两组方法。一组在操作失败时抛出异常,另一组则返回特殊值(通常是 nullfalse)。

操作头部 (Front/First)尾部 (Rear/Last)
插入addFirst(e) / offerFirst(e)addLast(e) / offerLast(e)
失败抛异常 / 失败返回 false失败抛异常 / 失败返回 false
移除removeFirst() / pollFirst()removeLast() / pollLast()
空队列抛异常 / 空队列返回 null空队列抛异常 / 空队列返回 null
检查getFirst() / peekFirst()getLast() / peekLast()
查看不删除空队列抛异常 / 空队列返回 null空队列抛异常 / 空队列返回 null
栈操作push(e) (等价于 addFirst(e))
pop() (等价于 removeFirst())
peek() (等价于 peekFirst())
队列操作remove() (等价于 removeFirst())add(e) (等价于 addLast(e))
(继承自Queue)poll() (等价于 pollFirst())offer(e) (等价于 offerLast(e))
element() (等价于 getFirst())
peek() (等价于 peekFirst())
其他removeFirstOccurrence(Object o)removeLastOccurrence(Object o)
从前往后移除第一个匹配元素,成功返回true从后往前移除第一个匹配元素,成功返回true
contains(Object o)size()
iterator()descendingIterator() (从尾到头遍历)

Deque 核心特点

1.双端操作
这是Deque的核心。你可以在队列的头部尾部执行插入、删除和检查操作

2.替代角色

  • 作为队列 (FIFO): 使用 addLast(e) / offerLast(e) 添加元素到尾部,使用 removeFirst() / pollFirst() 从头部移除元素
  • 作为栈 (LIFO): 使用 push(e) / addFirst(e) 添加元素到头部(压栈),使用 pop() / removeFirst() 从头部移除元素(弹栈),使用 peek() / peekFirst() 查看栈顶元素而不移除,使用push(e), pop(), peek()时,明确表示你在将Deque当作栈使Deque 是官方推荐替代遗留 Stack 类的方案

3.容量限制
某些 Deque 实现(如 ArrayDeque)可能有固定容量限制。尝试在满队列中添加元素可能会导致异常或返回特殊值(取决于具体方法)

4.Null元素
Deque 的实现类可以允许或不允许null元素。ArrayDeque不允许null元素,而LinkedList允许。使用 null 元素时要特别小心,因为某些方法(如 removeFirstOccurrence(null))可能会产生歧义

5.非线程安全
Deque的标准实现类(ArrayDeque, LinkedList)不是线程安全的。线程安全方式使用外部同步机制(如 Collections.synchronizedDeque())或使用并发包下的实现(如 LinkedBlockingDeque

Deque实现类 ArrayDeque

ArrayDeque实现了Deque接口,基于动态数组的数据提供了双端队列的功能

public class ArrayDeque<E> extends AbstractCollection<E>implements Deque<E>, Cloneable, Serializable

ArrayDeque 构造方法

1.无参构造默认容量 16

// 创建一个初始容量为16的空队列
Deque<String> names = new ArrayDeque<>(); 

2.创建一个具有指定初始容量的空双端队列

//预分配足够空间存放大约1000个读数
Deque<Integer> sensorReadings = new ArrayDeque<>(1000); // 但注意的是 自动调整为2的幂
ArrayDeque<Integer> deque2 = new ArrayDeque<>(100); // 实际容量128

3.创建一个包含指定集合 c 中所有元素的双端队列
元素的顺序由集合的迭代器返回顺序决定

List<String> list = Arrays.asList("Apple", "Banana", "Orange");
// 创建包含["Apple", "Banana", "Orange"]的队列
Deque<String> fruitDeque = new ArrayDeque<>(list); 重要提示:
如果传入的集合 c 是 null,会抛出 NullPointerException。
如果传入的集合 c 中包含 null 元素,在添加过程中(调用 c.iterator().next() 时)
会抛出 NullPointerException,因为 ArrayDeque 不允许 null 元素

ArrayDeque 的数据结构及实现原理

数据结构

// 关键字段
transient Object[] elements; // 存储元素的数组
transient int head;          // 头部指针(指向当前首元素)
transient int tail;          // 尾部指针(指向下一个插入位置)

动态循环数组示意图
动态数组:数组的大小可随着数据量进行扩容
循环数组:数组的任何一点都可以被看作是起点或者终点

添加节点流程图

假设初始容量为 4(实际最小容量为 8,但为简化演示使用 4)初始状态
数组:[null, null, null, null]
head = 0, tail = 0(空队列)
索引:  0     1     2     3[null, null, null, null]↑head/tail步骤 1: 尾部添加 A (addLast("A"))
在tail位置插入A,tail后移:tail = (0 + 1) & 3 = 1
索引:  0     1     2     3["A", null, null, null]↑head ↑tail步骤 2: 尾部添加 B (addLast("B"))
在 tail 位置插入 B,tail 后移:tail = (1 + 1) & 3 = 2
索引:  0     1     2     3["A", "B", null, null]↑head       ↑tail步骤 3: 头部添加 C (addFirst("C"))
head 前移:head = (0 - 1) & 3 = 3(循环到末尾) 在 head 位置插入 C
索引:  0     1     2     3["A", "B", null, "C"]↑tail ↑head步骤 4: 尾部添加 D (addLast("D"))
在 tail 位置插入 Dtail 后移:tail = (2 + 1) & 3 = 3
此时 head == tail,触发扩容!
索引:  0     1     2     3["A", "B", "D", "C"]↑head/tail? (实际 head=3, tail=3)步骤 5: 扩容(关键步骤)
计算新容量:原容量 4 → 新容量 8(翻倍)
创建新数组:[null, null, null, null, null, null, null, null]
复制元素(按逻辑顺序重排)1.从原head开始:复制索引3"C" → 新数组索引 02.继续循环:复制索引0"A" → 新数组索引 13.复制索引1"B" → 新数组索引 24.复制索引2"D" → 新数组索引 3
重置指针:
head = 0(新数组头部)
tail = 4(新数组尾部下一个空位)
新数组索引: 0    1    2    3    4    5    6    7["C", "A", "B", "D", null, null, null, null]↑head                ↑tail再新增节点
头部添加 E (addFirst("E"))
head 前移:head = (0 - 1) & 7 = 7(循环到末尾),在 head 位置插入 E
索引:  0    1    2    3    4      5     6    7["C", "A", "B", "D", null, null, null, "E"]↑tail             ↑head尾部添加 F (addLast("F"))
在 tail 位置插入 F,tail 后移:tail = (4 + 1) & 7 = 5
索引: 0    1    2    3    4     5     6     7["C", "A", "B", "D", "F", null, null, "E"]↑tail        ↑head直到两种会师 那就再次扩容 2倍扩容

删除节点流程图

头部移除 (removeFirst())
取出 head 位置元素 "E",置空 head 位置
head 后移:head = (7 + 1) & 7 = 0
索引:  0    1    2    3    4    5     6     7["C", "A", "B", "D", "F", null, null, null]↑head                    ↑tail尾部移除 (removeLast())
tail 前移:tail = (5 - 1) & 7 = 4
取出 tail 位置元素 "F" 置空 tail 位置
索引:   0    1    2    3    4    5     6     7["C", "A", "B", "D", null, null, null, null]↑head     		  ↑tai

ArrayDeque 方法介绍

操作方法时间复杂度说明
头部插入addFirst(E), push(E)O(1)插入失败抛出异常
offerFirst(E)O(1)插入失败返回 false
头部移除removeFirst(), pop()O(1)空队列抛出异常
pollFirst()O(1)空队列返回 null
头部查看getFirst(), peek()O(1)空队列抛出异常
peekFirst()O(1)空队列返回 null
尾部插入addLast(E), add(E)O(1)插入失败抛出异常
offerLast(E), offer(E)O(1)插入失败返回 false
尾部移除removeLast()O(1)空队列抛出异常
pollLast()O(1)空队列返回 null
尾部查看getLast()O(1)空队列抛出异常
peekLast()O(1)空队列返回 null
大小检查size()O(1)通过 head 和 tail 计算
包含检查contains(Object)O(n)线性搜索
清空clear()O(n)遍历数组置 null

ArrayDeque 核心特性

  1. 基于循环数组实现
    • 底层使用动态数组(Object[])存储元素。
    • 通过两个指针(head 和 tail)实现循环数组,head 指向队列的第一个元素,tail 指向队列末尾的下一个空位。
    • 当数组满时会自动扩容(通常翻倍),并将元素复制到新数组。
  2. 高效的头尾操作
    • 队列两端(头部和尾部)添加或移除元素的时间复杂度为 O(1)(摊销时间,因涉及扩容操作
    • 具体方法包括:
      • 头部操作:addFirst(), offerFirst(), removeFirst(), pollFirst(), getFirst(), peekFirst()
      • 尾部操作:addLast(), offerLast(), removeLast(), pollLast(), getLast(), peekLast()
  3. 不允许 null 元素
    • 试图添加 null 元素会抛出 NullPointerException。
  4. 非线程安全
    • 不是线程安全的类,如果需要在多线程环境下使用,必须通过外部同步机制(如 Collections.synchronizedDeque)来保证线程安全。
  5. 迭代快速失败(Fail-Fast)
    • 迭代器是快速失败的,如果在迭代过程中队列被修改(除了通过迭代器自身的 remove 方法),会抛出 ConcurrentModificationException。
  6. 用作栈和队列
    • 作为栈使用时(后进先出,LIFO),推荐使用 push(等同于 addFirst)和 pop(等同于 removeFirst)方法。
    • 作为队列使用时(先进先出,FIFO),推荐使用 add(等同于 addLast)和 remove(等同于 removeFirst)或 offerpoll 方法。
  7. 性能优势
    • 相比 LinkedList,ArrayDeque 在大多数场景下有更好的性能(尤其作为队列或栈),因为基于数组实现,内存局部性更好,减少了指针操作的开销。
  8. 初始容量
    • 默认初始容量为 16,也可以指定初始容量(必须是 2 的幂,如果不是,会自动调整为最接近的 2 的幂)。
    • 扩容策略:当数组满时,容量翻倍(变为原来的 2 倍)。
  9. 元素顺序
    • 迭代顺序是从头部(head)到尾部(tail),即队列中元素的顺序

ArrayDeque 总结

使用场景

场景推荐操作
FIFO 队列offerLast(e)pollFirst()
LIFO 栈push(e) (=addFirst(e)) , pop() (=removeFirst())
滑动窗口头尾快速插入/删除(如 LeetCode 239)
任务调度高效管理待执行任务队列
历史记录固定容量实现 LRU(需配合移除逻辑)

注意事项

场景原因
需要存储 null设计禁止 null 元素
高频随机访问按索引访问中间元素需遍历(改用 ArrayList
多线程无锁环境非线程安全(改用 ConcurrentLinkedDequeLinkedBlockingDeque
精确控制容量增长扩容策略固定为翻倍(若需定制策略需自行实现)

ArrayDeque 使用样例代码

// 1. 作为栈使用(LIFO)
Deque<Integer> stack = new ArrayDeque<>();
stack.push(1);      // addFirst(1)
stack.push(2);
int top = stack.pop(); // removeFirst() → 2// 2. 作为队列使用(FIFO)
Deque<String> queue = new ArrayDeque<>(1000); // 预分配容量
queue.offer("A");   // addLast("A")
queue.offer("B");
String first = queue.poll(); // removeFirst() → "A"// 3. 双端操作
ArrayDeque<Character> deque = new ArrayDeque<>();
deque.addFirst('X'); // [X]
deque.addLast('Y');  // [X, Y]
deque.removeFirst(); // [Y]
deque.removeLast();  // []

Deque实现类 LinkedList

LinkedList是整个集合框架中最灵活的类之一,因为它同时实现了List Qeque Deque 三个数据结构
LinkedList详情介绍链接

Deque实现类 ConcurrentLinkedDeque (非阻塞线程安全)

ConcurrentLinkedDeque是线程安全的无界双端队列,采用无锁算法CAS实现,支持在队列两端进行高效并发操作。它是ConcurrentLinkedQueue的双端队列版本

public class ConcurrentLinkedDeque<E>extends AbstractCollection<E>implements Deque<E>, java.io.Serializable {}

基本队列的非阻塞线程安全ConcurrentLinkedQueue 对比

特性ConcurrentLinkedDequeConcurrentLinkedQueue
操作端双端(头尾操作)单端(尾部入队,头部出队)
特殊方法addFirst(), removeLast()
数据结构双向链表单向链表
内存开销更高(每个节点两个指针)较低
使用场景更广泛标准队列场景

ConcurrentLinkedDeque 核心特性

1.线程安全:基于无锁算法(CAS)实现
2.双端操作:支持队列头部和尾部的插入/移除
3.无界队列:理论上可无限扩展(受内存限制)
4.非阻塞:操作不会导致线程阻塞
5.FIFO/LIFO 混合:可作为队列或栈使用
6.不允许 null 元素:插入 null 会抛出 NullPointerException

阻塞和非阻塞的主要区别在于是否等待对方响应
阻塞调用是指调用结果返回之前,当前线程会被挂起,一直处于等待消息通知,不能执行其他业务
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程

ConcurrentLinkedDeque 是非阻塞线程的特性区别对比 阻塞线程的类

特性阻塞队列 (如 ArrayBlockingQueue)非阻塞队列 (ConcurrentLinkedDeque)
线程挂起竞争失败时挂起等待失败时自旋重试,无挂起
开销上下文切换开销大无上下文切换,仅 CPU 自旋
吞吐量高竞争下下降显著高并发场景下更优

简单来说:阻塞的竞争失败挂起等待,非阻塞的不挂起不断重试直到成功,所以性能开销更大点

ConcurrentLinkedDeque 方法

头部操作

  • void addFirst(E e) / boolean offerFirst(E e):头部插入元素
  • E removeFirst() / E pollFirst():移除并返回头部元素
  • E getFirst() / E peekFirst():查看但不移除头部元素

尾部操作

  • void addLast(E e) / boolean offerLast(E e):尾部插入元素
  • E removeLast() / E pollLast():移除并返回尾部元素
  • E getLast() / E peekLast():查看但不移除尾部元素

通用操作

  • boolean add(E e):尾部添加(等价于 addLast
  • E remove():头部移除(等价于 removeFirst
  • E element() / E peek():查看头部元素

ConcurrentLinkedDeque 数据结构和实现原理

数据结构:双向链表节点
双向链表节点结构

private static final class Node<E> {volatile Node<E> prev;  // 前驱指针volatile E item;        // 存储元素volatile Node<E> next;  // 后继指针// CAS 操作方法boolean casItem(E cmp, E val) { /*...*/ }void lazySetNext(Node<E> val) { /*...*/ }boolean casNext(Node<E> cmp, Node<E> val) { /*...*/ }// ... 类似的前驱指针操作方法
}

队列头尾指针分离

   private transient volatile Node<E> head;private transient volatile Node<E> tail;

实现原理
核心点
1.数据结构:双向链表节点(Node)
2.无锁算法:使用CAS操作更新指针
3.头尾指针:volatile修饰的头节点(head)和尾节点(tail)
4.协作式删除机制:逻辑删除(标记item为null)和物理删除(解除链接)
5.一致性:弱一致性迭代器和视图
6.惰性更新策略:头尾指针不总是精确指向端点
7.最终一致性:通过后续操作逐步修正位置

已元素删除算法(以 pollFirst 为例)

public E pollFirst() {restartFromHead:for (;;) {// 步骤1:定位头节点Node<E> h = head, p = h;// 步骤2:查找首个有效节点while (p.item == null) {Node<E> next = p.next;if (next == null) return null;  // 队列为空p = next;}// 步骤3:逻辑删除 (标记item为null)if (!p.casItem(p.item, null)) continue;// 步骤4:物理解除链接Node<E> next = p.next;if (next != null && next.prev == p) {next.casPrev(p, p.prev);  // 更新后继的前驱}Node<E> prev = p.prev;if (prev != null && prev.next == p) {prev.casNext(p, p.next);  // 更新前驱的后继}// 步骤5:更新头指针if (p != h) {updateHead();  // 惰性更新head}return p.item;}
}

协作式删除节点
在步骤3:逻辑删除 (标记item为null)

// 在指针中嵌入状态信息(实际通过节点状态实现)
if (node.item == null) {// 节点已被删除,需要特殊处理helpUnlink(node);  // 协助解除链接continue;         // 重试操作
}

当线程A尝试删除节点X时:先将 X.item 置为 null(逻辑删除)
线程B若发现 X.item == null:主动调用 helpUnlink(x) 协助物理解除链接,更新相邻节点的指针
减少不必要的CAS操作

线程A: 设置X.item=null
线程B: 发现X.item=null
线程B: 尝试更新X.prev.next
线程B: 尝试更新X.next.prev
物理解除链接成功

迭代器实现原理:弱一致性迭代器

public Iterator<E> iterator() {return new Itr();
}private class Itr implements Iterator<E> {private Node<E> nextNode;private E nextItem;Itr() {advance();  // 初始化时获取首个有效节点}void advance() {// 从当前节点开始查找下一个有效节点do {nextNode = (nextNode == null) ? first() : nextNode.next;} while (nextNode != null && nextNode.item == null);nextItem = (nextNode != null) ? nextNode.item : null;}
}

特点:
快照隔离:迭代开始时获取当前头指针
跳过已删除节点:自动过滤 item == null 的节点
弱一致性:可能反映迭代开始后的部分修改

惰性更新策略

//前向指针修正:
void fixPrev(Node<E> p) {for (;;) {Node<E> q = p.prev;Node<E> next = p.next;if (q != null && q.next != p) {q.casNext(q.next, p);  // 修复前驱的后继}if (next != null && next.prev != p) {next.casPrev(next.prev, p);  // 修复后继的前驱}// 检查是否修复完成if ((q == null || q.next == p) && (next == null || next.prev == p)) {break;}}
}

修复后,最终一致性

设计亮点
1.无锁并发:基于 Michael-Scott 算法的双端扩展,使用 CAS 实现线程安全
2.惰性更新策略:不立即更新反向指针(允许暂时不一致), 后续操作会修复不一致状态
3.删除标记技术:协作删除:线程A的物理删除 和 后续线程B的物理删除
4.自我修复机制:线程遇到不一致状态时主动修复链表,保证最终一致性

ConcurrentLinkedDeque 总结

性能总结

操作时间复杂度并发性能
addFirst()O(1)极高
pollLast()O(1)
size()O(n)
contains()O(n)

注意事项

1.弱一致性方法

  • size() 需要遍历整个链表,结果可能过时
  • contains() 可能返回瞬时状态
  • 迭代器是弱一致性的

2.内存消耗

  • 每个元素需要额外两个指针(prev/next)
  • 比单向链表多 50% 内存开销

3.精确性要求

   // 不要依赖size()进行关键决策if (deque.size() > threshold) {// 这个判断可能不可靠!}

适用场景

1.工作窃取算法

   // 工作者线程从自己队列头部获取任务Runnable task = localDeque.pollFirst();// 当本地队列为空时,从其他队列尾部窃取if (task == null) {task = otherDeque.pollLast();}

2.多生产者-多消费者系统

  • 生产者可自由选择头部/尾部添加任务
  • 消费者可选择从头部/尾部获取任务

3.实时事件处理系统

  • 新事件添加到头部(高优先级)
  • 旧事件从尾部处理(低优先级)

4.并发缓存实现

  • 最近使用添加到头部
  • 淘汰策略从尾部移除

最佳实践

1.首选特定端方法

   // 明确意图deque.offerFirst(item); // 比 push() 更清晰

2.空队列处理

   // 使用poll而不是remove避免异常E item = deque.pollFirst();if (item != null) {// 处理元素}

3.批量处理优化

   // 批量提取多个元素List<E> batch = new ArrayList<>(BATCH_SIZE);while (batch.size() < BATCH_SIZE) {E item = deque.pollFirst();if (item == null) break;batch.add(item);}

和Deque其余子类 性能对比

操作ConcurrentLinkedDequeLinkedBlockingDequeArrayDeque (非线程安全)
头部插入 (100线程)12 ms45 msN/A
尾部插入 (100线程)13 ms48 msN/A
头部删除 (100线程)11 ms42 msN/A
内存开销 (100万元素)~48 MB~32 MB~24 MB

ConcurrentLinkedDeque 是 Java 并发编程中的高级工具:

  • 优势:高并发性能、双端操作、无界容量
  • ⚠️ 局限:内存开销大、弱一致性方法
  • 💡 适用:工作窃取、多端生产者-消费者系统、需要双端操作的并发场景

在需要高并发双端操作的场景下,ConcurrentLinkedDeque 提供了最优秀的并发性能,是构建高性能并发系统的理想选择

ConcurrentLinkedDeque 代码使用示例

1.作为并发栈(LIFO)

ConcurrentLinkedDeque<String> stack = new ConcurrentLinkedDeque<>();// 压栈
stack.push("Task1"); // addFirst
stack.push("Task2");// 弹栈
String task = stack.pop(); // removeFirst

2.作为双端队列

ConcurrentLinkedDeque<Integer> deque = new ConcurrentLinkedDeque<>();// 生产者A - 尾部添加
new Thread(() -> {for (int i = 0; i < 100; i++) {deque.addLast(i); // 尾部添加}
}).start();// 生产者B - 头部添加
new Thread(() -> {for (int i = -1; i > -100; i--) {deque.addFirst(i); // 头部添加}
}).start();// 消费者 - 头部处理
new Thread(() -> {while (true) {Integer num = deque.pollFirst(); // 头部取出if (num != null) {System.out.println("Processed: " + num);}}
}).start();

ArrayDeque 与 LinkedList 对比

特性ArrayDequeLinkedList
数据结构动态循环数组双向链表
内存占用更紧凑(无节点开销)每个元素额外24字节
随机访问O(n)O(n)(实际更慢)
迭代性能更高(缓存友好)较低
插入/删除(头尾)O(1) 分摊时间O(1)
插入/删除(中间)O(n)O(1)(已知位置)
null 支持❌ 禁止✅ 允许
多线程安全❌ 需要外部同步❌ 需要外部同步
扩容成本较高(复制数组)

Deque总结

Deque 是一个功能强大且灵活的接口,统一了队列和栈的抽象。它提供了丰富的双端操作方法(包括异常抛出型和特殊值返回型)。ArrayDeque 通常是需要高效双端操作且不需要 List 功能或 null 元素时的最佳选择。LinkedList 在需要同时使用 DequeList 功能或需要 null 元素时是唯一选择。理解不同方法的区别以及两种主要实现的特性,对于正确有效地使用 Deque 至关重要。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/87066.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/87066.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Spring】——事务、整合、注解

目录 一.Spring与mybatis的整合 1.配置文件 ​编辑2. 二.事务 1.事务属性 2.传播属性 3.异常属性 4.常见配置 三.注解 1.什么是注解 2.Autowired 1.用户自定义注解 ​编辑​编辑2.JDK类型注入value 3.Bean 1.对象的创建 2.对象创建次数 3.Bean注解的注入 1.自…

Linux 离线下安装gcc、g++

描述 离线时编译Redis、nginx等编译包&#xff0c;需要gcc安装包&#xff0c;评论提醒我 上传补充 操作 1、进入gcc目录&#xff0c;并执行安装命令 rpm -ivh *.rpm --nodeps --force查看版本 gcc -v2、进入gcc-c目录&#xff0c;并执行安装 rpm -ivh *.rpm --nodeps --f…

融智学定律3:流动创造价值仅当跨域协同

关键公式意义&#xff1a; 人流方程中的 α/β 反映城市吸引力不对称性 物流优化中的 η 实现时间价值货币化 金流模型的 σ(⋅) 捕捉市场情绪突变点 信息熵的 ∥gi​−gj​∥ 度量知识势差驱动 当五流在黎曼流形上满足 ∇_μ​T^μν0&#xff08;能量动量守恒&#xff09…

趣味数据结构之——数组

你们一定都听说过它的故事…… 是的没错&#xff0c;就是一个萝卜一个坑。ಥ◡ಥ 想象一下数组就是那个坑&#xff0c;那么定义数组就是在挖坑。 元素就是萝卜。 坑就在那里(地上)&#xff0c;整整齐齐地排在那里。 于是数组最重要的一个特性就显现出来了——随机存取。还…

PR-2025《Scaled Robust Linear Embedding with Adaptive Neighbors Preserving》

核心思想分析 这篇论文的核心思想在于解决线性嵌入&#xff08;linear embedding&#xff09;与非线性流形结构之间的不匹配问题。传统方法通过保留样本点间的亲和关系来提取数据的本质结构&#xff0c;但这种方法在某些情况下无法有效捕捉到数据的全局或局部特性。此外&#…

Redis-渐进式遍历

之前使用的keys查找key,一次获取到了所有的key,当key较多时,这个操作就有可能造成Redis服务器阻塞.特别是keys *操作. 于是可以通过渐进式遍历,每次获取部分key,通过多次遍历,既查询到了所有的key,又不会卡死服务器. 渐进式遍历不是通过一个命令获取到所有元素的,而是由一组命…

ISP Pipeline(3):Lens Shading Correction 镜头阴影校正

上一篇文章讲的是&#xff1a;ISP Pipeline&#xff08;2&#xff09;&#xff1a; Black Level Compensation:ISP Pipeline&#xff08;2&#xff09;&#xff1a;Black Level Compensation 黑电平补偿-CSDN博客 视频&#xff1a;(4) Lens Shading Correction | Image Signal…

什么是WebAssembly(WASM)

WebAssembly&#xff08;WASM&#xff09; 是一种高性能的低级编程语言字节码格式&#xff0c;可在网页和非网页环境中运行&#xff0c;支持多语言编译&#xff0c;运行速度接近原生代码。它在区块链中的作用是&#xff1a;作为智能合约的执行引擎&#xff0c;被多条非以太坊链…

【C++】inline的作用

一、inline的作用 1.1函数内联 作用​&#xff1a;建议编译器将函数调用替换为函数体代码&#xff0c;减少函数调用的开销&#xff08;压栈/跳转&#xff09;。​注意​&#xff1a;这只是对编译器的建议&#xff0c;编译器可能忽略&#xff08;如函数体过大或递归&#xff0…

代码随想录|图论|04广度优先搜索理论基础

广搜的使用场景 广搜的搜索方式就适合于解决两个点之间的最短路径问题。 因为广搜是从起点出发&#xff0c;以起始点为中心一圈一圈进行搜索&#xff0c;一旦遇到终点&#xff0c;记录之前走过的节点就是一条最短路。 当然&#xff0c;也有一些问题是广搜 和 深搜都可以解决…

Xposed框架深度解析:Android系统级Hook实战指南

引言:Android系统定制化的革命性突破 在移动安全研究和系统优化领域,传统的APP修改方案面临​​三重技术瓶颈​​: ​​逆向工程壁垒​​:APK重打包方案需处理签名校验、代码混淆等防护,平均耗时增加200%​​兼容性挑战​​:Android碎片化导致设备适配率不足65%​​功能…

大模型在通讯网络中的系统性应用架构

一、网络架构智能化重构​​ ​​1.1 空天地一体化组网优化​​ 智能拓扑动态调整​​&#xff1a;大模型通过分析卫星轨道数据、地面基站负载及用户分布&#xff0c;实时优化天地一体化网络拓扑。例如&#xff0c;在用户密集区域&#xff08;如城市中心&#xff09;自动增强低…

软件测试进阶:Python 高级特性与数据库优化(第二阶段 Day6)

在掌握 SQL 复杂查询和 Python 数据库基础操作后&#xff0c;第六天将深入探索Python 高级编程特性与数据库性能优化。通过掌握 Python 的模块与包管理、装饰器等高级语法&#xff0c;结合数据库索引优化、慢查询分析等技术&#xff0c;提升测试工具开发与数据处理效率。 一、…

【NLP】自然语言项目设计04

目录 04模型验证 代码架构核心设计说明 05运行推理 代码架构核心设计说明 项目展望 项目简介 训练一个模型&#xff0c;实现歌词仿写生成 任务类型&#xff1a;文本生成&#xff1b; 数据集是一份歌词语料&#xff0c;训练一个模型仿写歌词。 要求 1.清洗数据。歌词语料…

数据结构1 ——数据结构的基本概念+一点点算法

数据结构算法程序设计 什么是数据结构 数据&#xff08;data&#xff09;&#xff1a;符号集合&#xff0c;处理对象。 数据元素&#xff08;data element&#xff09;&#xff0c;由数据项&#xff08;data item&#xff09; 组成。 关键字&#xff08;key&#xff09;识别…

每日八股文7.1

每日八股-7.1 网络1.能说说 TCP 报文头部都包含哪些关键字段吗&#xff1f;2.TCP 是如何确保数据传输的可靠性的&#xff1f;你能详细谈谈吗&#xff1f;3.你能解释一下 TCP 滑动窗口是如何设计的&#xff1f;它主要解决了什么问题&#xff1f;4.TCP 协议的拥塞控制是如何实现的…

高性能 List 转 Map 解决方案(10,000 元素)

文章目录 前言一、问题背景&#xff1a;为什么List转Map如此重要&#xff1f;二、基础方法对比&#xff1a;Stream vs For循环三、性能优化关键点四、面试回答技巧 前言 遇到一个有意思的面试题&#xff0c;如标题所说&#xff0c;当10,000条数据的List需要转Map&#xff0c;如…

今日行情明日机会——20250701

上证指数缩量收阳线&#xff0c;形成日线上涨中继&#xff0c;个股上涨和下跌总体持平。 深证指数量能持续放大&#xff0c;即将回补缺口位&#xff0c;短线注意周三或周四的调整。 2025年7月1日涨停股主要行业方向分析 1. 芯片&#xff08;17家涨停&#xff0c;国产替代&…

P1312 [NOIP 2011 提高组] Mayan 游戏

题目描述 Mayan puzzle 是最近流行起来的一个游戏。游戏界面是一个 7 7 7 行 5 \times5 5 列的棋盘&#xff0c;上面堆放着一些方块&#xff0c;方块不能悬空堆放&#xff0c;即方块必须放在最下面一行&#xff0c;或者放在其他方块之上。游戏通关是指在规定的步数内消除所有…

Spring Boot 2 多模块项目中配置文件的加载顺序

Spring Boot 2 多模块项目中配置文件的加载顺序 在 Spring Boot 2 多模块项目中&#xff0c;配置文件的加载遵循特定的顺序规则。了解这些规则对于正确管理多模块应用的配置至关重要。 一、默认配置文件加载顺序 Spring Boot 会按照以下顺序加载 application.properties 或 …