微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

具有快速最小、删除、插入、搜索大计算作业的数据结构

如何解决具有快速最小、删除、插入、搜索大计算作业的数据结构

我正在寻找一种数据结构,可以让我高效地执行所需的操作。我希望遍历 1011 和 1013 次之间的循环,因此 Ω(n) 操作是正确的。 (我会尝试减少 n 以便它可以放入缓存中,但不会小。)每次通过循环我都会调用

  • 分钟恰好一次
  • 删除一次(删除最小值,如果有帮助)
  • 插入 0 到 2 次,平均略多于 1
  • 为每个插入搜索一次

我只关心平均或摊销后的表现,而不是最坏的情况。 (计算需要很长时间,如果计算的位不时停顿也没关系。)数据不会是对抗性的。

我应该考虑什么样的结构?也许有某种堆被修改以进行快速搜索

解决方法

A balanced tree 是一种非常适合这种用法的数据结构。所有指定的操作都在 O(log n) 中计算。我认为您可以编写一个优化的树实现,以便可以在 O(1) 中检索最小值(通过将迭代器保留到最小值和可能的值以加快获取速度)。算法的结果时间将为 O(m log n),其中 m 是迭代次数,n 是数据结构中的项目数。

这是最佳算法复杂度。事实上,假设每次迭代都可以在(摊销)O(1) 中完成,那么四个操作中的每一个也必须具有这样的复杂性。让我们假设可以使用这样的属性构建数据结构 S。可以编写以下算法(用 Python 编写):

def superSort(input):
    s = S()
    inputSize = len(input)
    for i in range(inputSize):
        s.insert(item[i])
    output = list()
    for i in range(inputSize):
        output.append(s.getMin())
        s.deleteMin()
    return output

superSort 的(摊销)复杂度为 O(n)。然而,基于比较的排序 has been proven 的理论最优精确算法复杂度为 O(n log (n))。因此,S 不存在,并且至少需要在至少 O(log n) 时间内完成 4 个操作中的至少一个。

请注意,朴素的二叉树实现通常效率很低。您可以执行许多优化来使它们更快。例如,您可以打包节点(参见 B-trees),将节点放入一个数组中(假设项目的数量是有界的),使用可能基于随机属性的宽松平衡(参见 Treaps) 、使用小引用(例如 16 位索引或 32 位索引而不是 64 位指针)等。您可以从简单的 AVLsplay-tree 开始。

,

我建议的数据结构需要更多的工作来实现,但它确实达到了预期的结果; 可以使用 AVL 树实现具有 {insert,delete,findMin,search} 操作的数据结构,该树确保每个操作在 O(logn) 中完成,而 findMin 在 O(1) 中完成。

我将深入研究一下实现:

树将包含一个指向最小节点的指针,该节点在每次插入和删除时更新,因此 findMin 需要 O(1)

insert 在每个采用 O(logn) 的 AVL 树中实现(使用平衡因子和旋转/交换来平衡树)。插入元素后,您需要通过从树的根部一直向左移动来更新最小节点指针,这也需要 O(logn),因为树的高度是 O(logn)

同样,在使用 delete 后,您需要以相同的方式更新最小指针,因此它需要 O(logn)

最后,search 还需要 O(logn)

如果给出更多假设,例如插入的元素在最小值的一定范围内,那么你也可以给树中的每个节点successorpredecessor指针,在插入和删除时也可以在O(logn)中更新,因此可以在 O(1) 中访问而无需遍历整个树。并且可以更快地搜索插入的元素。

插入节点的后继可以通过转到右孩子然后一直到左边来更新。但是,如果右孩子不存在,那么只要当前节点不是其父节点的左孩子,您就需要爬上父节点。 前驱以完全相反的方式更新。

在 C++ 中,节点看起来像这样

template <class Key,class Value>
class AvlNode{
private:
    Key key;
    Value value;
    int Height;
    int BF; //balance factor
    AvlNode* Left;
    AvlNode* Right;
    AvlNode* Parent;
    AvlNode* Succ;
    AvlNode* Pred;

public:
...
}

虽然树看起来像这样:

template <class Key,class Value>
class AVL {
private:
    int NumOfKeys;
    int Height;
    AvlNode<Key,Value> *Minimum;
    AvlNode<Key,Value> *Root;

    static void swapLL(AVL<Key,Value> *avl,AvlNode<Key,Value> *root);
    static void swapLR(AVL<Key,Value> *root);
    static void swapRL(AVL<Key,Value> *root);
    static void swapRR(AVL<Key,Value> *root);

public:
...
}
,

从你告诉我们的情况来看,我想我会使用一个开放寻址的哈希表进行搜索,并使用一个堆来跟踪最小值。

在堆中,您将存储指向哈希表中项目的索引/指针,而不是存储值。这样当你从堆中删除min时,就可以按照指针从hash表中找到需要删除的项。

每个项目的总内存开销将是 3 或 4 个字——与平衡树大致相同,但实现更简单、更快。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。