【问题标题】:Good data structure to hold a list保存列表的良好数据结构
【发布时间】:2015-06-30 14:15:09
【问题描述】:

我需要一个包含有序列表的数据结构。我需要有一个插入、一个删除操作以及一个 getPosition 操作。

getPosition 操作经常在连续元素上调用,例如我有一个列表:

[a0, a1, …, ak, ak', …, an]

我需要经常获取ak 的索引,然后是ak' 的索引。

我在想类似于伸展树的算法,但它也可以移动访问元素的邻居可能是有效的,但我找不到任何参考。你有什么建议吗?

编辑: 我还需要快速插入+删除。 O(log(n)) 中的东西就足够了。

【问题讨论】:

  • 一旦你有了ak的位置,你就有了ak'的位置,不是吗?
  • 是的,但是由于您检查了ak位置,因此可能发生了插入或删除,因此之前计算的位置可能不再相关。
  • 看看 linux 进程调度器。有一个很适合你的情况。它用于 CFS(完全公平的调度程序)。它使用 RBTree,但是,有一个额外的双向链表以按顺序遍历顺序将所有节点链接在一起。这种冗余可以将后继和前继操作减少到O(1),同时保持删除和插入O(lg n)

标签: algorithm list binary-search-tree


【解决方案1】:

Skip List 怎么样?这应该允许您保留一个有序列表,并为您提供 O(log n) 的插入、删除和搜索性能(平均)。

在优化元素k+1的搜索方面,也许只是缓存最后搜索的索引并从那里开始搜索。

【讨论】:

    【解决方案2】:

    一个解决方案,但不是很好:

    由于getPosition操作被称为“频繁”,我认为你的节点应该是这样的:

    struct node {
        int key;
        int index;
        node *next;
        node *last;
    }
    

    每次添加或删除节点时,都会遍历列表的其余部分并更新索引。

    更好的解决方案:

    您可以使用树结构,其中所有节点都保存在叶节点中,每个根都保存其下的叶数。 InsertDeletegetPostion 应该是 O(log n)

    【讨论】:

    • 是的,但这意味着插入和删除运行在 O(n) 中,n 是我的列表的长度,而二叉树会给我 O(log(n)),但 getPosition 较慢.我正在更新问题以强调快速插入和删除的必要性。
    • 索引有什么帮助?你仍然需要遍历所有节点
    • 至于你更好的解决方案,我完全同意,但是你有什么建议可以从最近访问的叶子的邻居很快被访问这一事实中受益吗?
    • 是的。找到他们的 LCA,这应该会(不是渐近地)变得更好。最坏的情况是,他们的 LCA 是根,这将毫无用处。此外,每个节点都可以保存指向其邻居的指针,然后如果您在ak 之后立即获得ak',您可以检查它是否是您刚刚检索到的最后一个节点的邻居,并且您知道该位置是+1之前
    猜你喜欢
    • 2021-04-16
    • 1970-01-01
    • 1970-01-01
    • 2012-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-27
    相关资源
    最近更新 更多