用ArrayDeque的addLast()和removeFirst()实现滑动平均,核心是维护固定长度双端队列并增量更新runningSum,每次push操作时间复杂度O(1),平均值为runningSum/window.size()。

用 ArrayDeque 的 addLast() 和 removeFirst() 实现滑动平均,核心在于维护一个固定长度的双端队列,只保留窗口内最新数据,每次新增+移除都在 O(1) 时间完成,避免重复遍历或数组拷贝。
保持窗口大小恒定
滑动平均的关键是「只算最近 N 个数」。用 ArrayDeque 存储原始数值(如 Double 或 int),每来一个新值:
→ 调用 addLast(newVal) 加入队尾;
→ 若队列长度超过窗口大小 N,立刻调用 removeFirst() 剔除最老值。
这样队列始终只含有效窗口内的元素,无需索引计算或边界判断。
增量更新总和,避免重复求和
不要每次调用 stream().mapToDouble(...).average()——那会遍历整个队列,退化为 O(N)。应维护一个运行总和 runningSum:
- 加入新值时:
runningSum += newVal - 移出旧值时:
runningSum -= removedVal - 平均值直接用
runningSum / deque.size()(注意 size() 始终 ≤ N,且当队列未满时按实际数量算)
处理初始阶段(队列未满)
前 N−1 次输入时,窗口未填满,平均值应基于已进入的元素个数。ArrayDeque.size() 天然反映当前有效长度,所以无需额外计数器。例如窗口大小为 5,第 3 次调用后 deque.size() == 3,平均值就是前三数之和 ÷ 3。
代码片段示意(Java)
以下是最简实用结构:
class SlidingAverage {
private final ArrayDeque<Double> window = new ArrayDeque<>();
private final int capacity;
private double runningSum = 0.0;
SlidingAverage(int windowSize) {
this.capacity = windowSize;
}
double push(double value) {
window.addLast(value);
runningSum += value;
if (window.size() > capacity) {
double oldest = window.removeFirst();
runningSum -= oldest;
}
return runningSum / window.size();
}
}
注意:ArrayDeque 是非线程安全的,高并发场景需加锁或改用 ConcurrentLinkedDeque(但后者不保证 O(1) 的 size(),慎用)。


















