快速中位数更新算法
Algorithm for Fast Median Update
假设在某个时间点,您有一个N
数字的集合,并且知道中位数元素:M
。现在,您将获得一个新值 X
,因此您可能需要更新M
。(或者更确切地说,你需要这样做,假设你正在处理的数字都是唯一的。此外,所有示例都是按顺序接收的,因此不存在并发问题。
计算新平均值很简单:取旧平均值,加X
,乘以N
,然后除以N + 1
。(通过检查如何定义 N 个元素的平均值可以清楚地看出这一点。目前,我不太担心数字。
我的问题是:任何人都可以建议一种创造性/小说(或者也许是可证明的最佳(来解决更新中位数的问题吗?我将在下面提供一个例子(我自己设计的简单想法(,并进行一些分析:
在此示例中,我将使用 std::forward_list
,因为 C++11 是我最近遇到此问题的地方。在不失去一般性的情况下,我将假设您正在以正确的方式执行此操作:维护到目前为止遇到的元素(类型 T(的有序列表,std::forward_list<T> sorted;
当T x;
出现时,只需使用以下方法将其折叠到位:
sorted.merge(std::forward_list<T> {{ x }});
顺便说一句,我很好奇是否有人有更好(更有效/优雅(的方法。欢迎抱怨。
所以,X
现在是sorted
的一部分,简而言之,这是我的想法:
auto it = sorted.begin(), itend = sorted.end();
typename std::forward_list<T>::size_type count = std::distance(it, itend);
for (const auto &e : sorted) {
if (it == itend || ++it == itend) {
M = (count % 2) ? e : (e + M) / 2;
break;
} else { ++it; }
}
这里发生的好事(如果不是有点难看(是:由于您将迭代器向前移动两次(并且安全,我可能会添加,尽管以两次比较为代价(,当达到end()
时,我们将处于正确的(中位数(值。如果元素数量为奇数,则M
只是该样本,如果没有,则只是该元素的平均值和旧的(推出的(中位数。由于奇数和偶数交替出现,因此旧M
或新实际上将位于集合中。这个推理是合理的,是吗?
如果您认为我的 O(3n( 方法/您的方法要好得多,则无需评论它;我只是建议将其作为一个起点。
您可以使用std::set
,并且插入集合不会使迭代器无效。
是奇数,则可以将迭代器mIt
集合的中位数元素N
如果N
是偶数,则可以将其保留在两个中位数元素的左侧。
让我们考虑一下插入元素时可能遇到的不同情况:
N
时插入是奇数:如果插入的元素小于 *mIt
,则旧的中位数变为两个新中位数元素的右边,因此递减迭代器。如果它更大(或相等,对于multiset
(,一切都很好。N
为偶数时的插入:如果插入的元素大于(或等于(*mIt
,则旧的右中位数变为中位数,因此请增加迭代器。如果它更小,旧的左中位数就会变成中位数,一切都很好。
template <class T>
class MedianHolder {
std::set<T> elements;
std::set<T>::const_iterator mIt;
public:
T const& getMedian() const { return *mIt; }
void insert(T const& t) {
if (elements.empty()) {
mIt = elements.insert(t).first;
return;
}
bool smaller = std::less<T>(t,getMedian());
bool odd = (elements.size() % 2) == 1;
if (!elements.insert(t).second)
return; //not inserted
if (odd && smaller) --mIt;
else if (!odd && !smaller) ++mIt;
}
};
我会把擦除元素留给你作为练习;-(
您可以将数组拆分为两个大小相等的堆树,I
最少部分或数组,并且S
是最大的部分,它们的顶部包含最大和最小元素。假设数组1, 2, 4, 4, 5, 5, 7, 8, 8, 8
像这样组织:
1 4
/
4 2
/
5 <--- I's top
5 <--- S's top
/
7 8
/
8 8
请注意,如果元素数是偶数,则中位数 = top(S(+top(I(,如果奇数,则堆中的一个元素比另一个元素大,中位数位于较大的元素之上。
完成此操作后,更新中位数很简单,您应该将元素添加到其中一个堆中,如果 top(S( 小于 top(I(,则交换它们的顶部。
- 从C++本机插件更新Vector3数组
- QGraphicsPolygonItem在拖动时未更新QPolygonF坐标
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 基于ELO的团队匹配算法
- C++选择排序算法中的逻辑错误
- 有没有办法将谓词中的元素偏移量传递给 std 算法?
- C++A*算法并不总是在路径中具有目标节点
- 排序算法c++
- cmake更新缓存的变量
- 构建可组合有向图(扫描仪生成器的汤普森构造算法)
- 算法问题:查找从堆栈中弹出的所有序列
- 下面是排序算法O(n)吗
- 更新到莫哈韦后出现cmath错误
- KMP算法和LPS表构造的运行时间
- OpenMP:并行更新数组总是需要减少数组吗
- 为什么我的排序算法会更改数组值
- 求最大元素位置的分治算法
- 具有非整数边容量的最大流量的Dinic算法
- 在某些范围更新后获取整数数组的最终状态的有效算法是什么?
- 快速中位数更新算法