【问题标题】:Data-structure with TTL带有 TTL 的数据结构
【发布时间】:2013-11-19 16:55:06
【问题描述】:

我想用这样的属性构建键值存储:

  • O(log N) 插入复杂度和写入优化;
  • 顺序写入的插入速度更快(键按顺序排列,有间隙);
  • O(log N) 键查找复杂度;
  • O(log N + M) 键范围查询复杂度;
  • o(N) 过时的密钥驱逐复杂度;
  • 所有键都有与之关联的时间戳,旧项目会定期被驱逐;
  • 必须通过调用某个函数或方法显式地完成键逐出;
  • 如果密钥已过期,仍然可以读取;
  • key eviction 不需要非常精确;

所以界面可以是这样的:

template<class K, class V>
class Index {
    ...
    class iterator_pair...
    ...
    Index(int TTL);
    void insert(K key, V value);
    V find(K key);
    iterator_pair<K, V> get_range(K begin, K end);
    void remove_outdated();
};

如何实现这样的数据结构?

更新

到目前为止一切顺利,我决定使用 TSB-tree(时间分割 b+ 树)来实现这一点。它几乎完美契合——写入和键查找具有对数复杂度;它是写优化的(大多数插入只是写入预分配的内存缓冲区,分配由许多插入摊销);旧的密钥驱逐可以通过删除历史节点来完成,并且这个节点可以很容易地标记以便快速访问,甚至更多 - 可以在节点拆分期间完成密钥驱逐。

基于 RB-tree 的解决方案也非常有效,也许我用它代替 TS​​B-tree 因为易于实现(与 TSB-tree 相比)。

【问题讨论】:

  • O(N log N) 对于范围查询来说是一个相当宽松的界限。我的意思是,即使是未排序的数组也会给你 O(N)。您的意思是 O(log N + M),其中 M 是实际范围内的元素数?
  • 感谢您的指正:)
  • 这看起来很像 C++ - 你想添加那个标签吗?另外,关键是你的时间戳,还是基于其他东西的驱逐?
  • 密钥和时间戳是不同的东西。当新的键值对添加到集合中时,必须在内部生成时间戳。

标签: c++ algorithm data-structures


【解决方案1】:

听起来您只需要一个红黑树(可能是连续的键值数组,以满足您的第二个要求),并覆盖有插入顺序的链表。 (如果您不一定要按时间戳升序插入键,请将其设为斐波那契堆而不是链表。)

顺便说一句,我假设您的倒数第二点是您的意思是“尝试查找引用过期项目的密钥不是错误”。

【讨论】:

  • “尝试查找引用过期项目的密钥不是错误” - 正确,如果该项目没有通过密钥驱逐程序从集合中删除。
  • +1。如果没有范围查询要求,字典或哈希映射(与链表结合)可以工作。
  • 我不完全了解如何优化 rb-trees 以进行写入。你能澄清一下吗?
  • 它们已经是最优的——插入是 O(log n)。 “写优化”还有什么意思吗?
  • 写优化是指索引大量插入的能力,即使以更慢的读取为代价。例如,在一些 b+tree 实现中,项目以插入顺序附加到某个叶缓冲区而不进行排序。为了写入性能,牺牲了读取性能(不可能对节点数据使用二进制搜索)。
【解决方案2】:

其实你可以维护一个有序的std::deque

这应该符合您的所有标准并允许调整周期大小(驱逐)

【讨论】:

  • 排序的双端队列不允许 O(log n) 插入。
  • @Ben 不清楚 key 是否是时间顺序的,因此所有插入都是前插入
  • 仅当 key=timestamp 时。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
  • 1970-01-01
  • 1970-01-01
  • 2015-03-29
  • 2019-07-09
  • 1970-01-01
  • 2020-05-06
相关资源
最近更新 更多