如何进一步优化此数据结构?

时间:2014-09-17 17:44:01

标签: algorithm data-structures time-complexity

最近我被要求构建一个支持四种操作的数据结构,即

  1. 推送:向DS添加元素。
  2. Pop:删除最后一个被推送的元素。
  3. Find_max:查找当前存储元素中的最大元素。
  4. Pop_max:从DS中删除最大元素。
  5. 元素是整数。

    以下是我建议的解决方案:

    1. 筹码。
    2. 在其中存储一对元素。该对应该是(element,max_so_far),其中 element 是该索引处的元素, max_so_far 是到目前为止看到的最大值元素。
    3. 将元素推入堆栈时,请检查最顶层堆栈元素的 max_so_far 。如果当前数字大于该值,则将当前对的 max_so_far 值作为当前元素的值,否则存储前一个 max_so_far 。这意味着推送只是O(1)操作。
    4. 对于pop,只需将一个元素弹出堆栈即可。同样,此操作为O(1)
    5. 对于Find_max,返回堆栈中最顶层元素的 max_so_far 的值。再次,O(1)
    6. 在分配新的 max_so_far 值之后,弹出max元素将涉及遍历堆栈并显式删除max元素并推回其顶部的元素。这将是线性的。
    7. 我被要求改进它,但我不能。

      就时间复杂度而言,如果所有操作都在O(logn)中发生,则可以提高整体时间。怎么做,是我无法得到的。

4 个答案:

答案 0 :(得分:8)

一种方法是将指针存储在双向链表中的元素中,也存储在max-heap数据结构中(按值排序)。

每个元素都会将其位置存储在双向链表中,也存储在最大堆中。

在这种情况下,所有操作在双向链表中需要O(1)时间,在堆数据结构中需要O(log(n))时间。

答案 1 :(得分:5)

获得O(log n)-time操作的一种方法是混合两个数据结构,在这种情况下是双向链表和优先级队列(配对堆是一个不错的选择)。我们有一个像

这样的节点结构
struct Node {
    Node *previous, *next;  // doubly linked list
    Node **back, *child, *sibling;  // pairing heap
    int value;
} list_head, *heap_root;

现在,推动,我们推进两个结构。对于find_max,我们返回配对堆的根值。要pop或pop_max,我们从适当的数据结构中弹出,然后使用其他节点指针在其他数据结构中删除。

答案 2 :(得分:2)

通常,当您需要按质量A(值)以及质量B(插入顺序)查找元素时,您就开始关注一个实际上有两个数据结构的数据结构,这个数据结构相互引用,否则交错。

例如:两个地图的关键字是质量A和质量B,谁的值是指向结构的共享指针,该结构包含返回两个地图的迭代器和值。然后你有log(n)通过任一质量找到一个元素,擦除是~O(logn)从两个map中删除两个迭代器。

struct hybrid {
    struct value {
        std::map<std::string, std::shared_ptr<value>>::iterator name_iter;
        std::map<int, std::shared_ptr<value>>::iterator height_iter;
        mountain value;
    };
    std::map<std::string, std::shared_ptr<value>> name_map;
    std::map<int, std::shared_ptr<value>> height_map;

    mountain& find_by_name(std::string s) {return name_map[s]->value;}
    mountain& find_by_height(int height h) {return height_map[s]->value;}
    void erase_by_name(std::string s) {
        value& v = name_map[s];
        name_map.erase(v.name_iter);
        height_iter.erase(v.height_iter); //note that this invalidates the reference v
    }
};

然而,在你的情况下,你可以做得比这个O(logn)更好,因为你只需要&#34;最新的&#34;和#34;下一个最高&#34;。使#&#34;流行音乐最高&#34;快速,你需要一种快速检测下一个最高的方法,这意味着需要在插入时预先计算。找到&#34;身高&#34;相对于其余的位置,你需要某种地图。使#&#34;弹出最新的&#34;很快,你需要一种快速的方法来检测下一个最近的,但这很简单。我建议创建一个映射或节点堆,其中键是查找最大值的值,值是指向下一个最新值的指针。这给你O(logn)插入,O(1)找到最近的,O(1)或O(logn)找到最大值(取决于实现),以及~O(logn)擦除任一索引。

答案 3 :(得分:0)

另一种方法是: -

使用元素创建max-heap。通过这种方式,我们将能够在O(1)操作中获取/删除max-element。 除此之外,我们可以维护一个指向最后推送元素的指针。据我所知,堆中的删除可以在O(log n)中构建。