具有堆和映射同等能力的数据结构

Datastructure with equivalent power of heap and map

本文关键字:能力 数据结构 映射      更新时间:2023-10-16

我想为元素e设计一个容器C

E有2个属性(优先级,名称),容器中的所有元素都有唯一的"名称"

我希望在容器C上尽可能高效地支持以下操作

  1. insert:-将element1(name1, priority1)插入到容器中:C.insert(元素(name1 priority1)
  2. update:-将name=name1作为优先级new1的元素更新优先级;C[name1] = priorityNew1
  3. delete:-删除name=name1的元素:C.delete(name1)
  4. 获取并移除优先级最高的元素:C.pop()
  5. 获取优先级最高的元素:C.peek()

基本上我想要map和heap的组合。映射元素的"名称",堆元素的"优先级"。最理想的情况是,我希望每个操作都是O(1)否则,插入、更新、删除的时间为O(log N), pop和peek的时间为O(1)也可以。

我能想到以下两种方法

1)使用元素的哈希映射,对名称进行哈希。所以插入、更新、删除都是0 (1)pop和peek是O(N),我们搜索整个容器的最高优先级。

2)使用SQLite,表'element'有两列'name'和'priority'。运行时间将基于SQLite实现。

我很想知道更多关于这个问题的想法,我正面临着一个与此相关的现实问题。

如果每个操作都可以接受O(logN),显然boost::bimap就足够了。这就像一个双面 std::map。您可以通过同时维护两个std::map或编写自己的包装器来获得几乎相同的结果(但是为什么要这样做呢?)对于最小检索,具有自平衡的二叉搜索树具有O(logN),其效率略低于堆。

如果效率真的那么重要,你应该用实现你自己的容器,同时使用堆和散列映射。然后,当您在堆中进行交换时,在散列映射中维护从name到堆数组中订阅的映射。这给了插入,删除,重分配优先级一个O(logN)O(1)最小/最大优先级元素。(这不是一块蛋糕实现,但也不繁琐)

我不知道Boost是否适合你,但我会检查Boost多重索引。http://www.boost.org/doc/libs/1_53_0/libs/multi_index/doc/index.html

你可以在优先级上保留一个in索引,这样你就可以快速获取这些元素,也可以插入元素。我对MRU/LRU情况使用了类似的boost多索引。

#include <iostream>
#include <string>
#include <algorithm>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/optional.hpp>
struct bypriority{};
struct byseq{};
struct MyElement{
    typedef int priority_type;
    typedef std::string name_type;
    name_type name;
    priority_type priority;
    MyElement(const name_type& name, const priority_type& priority):name(name),priority(priority){};
};
std::ostream& operator<<(std::ostream& os, const MyElement& e){
    os << "Name: " << e.name << " Priority: " << e.priority;
    return os;
}
using namespace boost;
using namespace boost::multi_index;
template<typename Element>
struct Container{
    typedef multi_index_container<
        Element,
        indexed_by<
            //sequenced
            sequenced<tag<byseq> >,
            //ordered by priority
            ordered_non_unique<tag<bypriority>,member<Element,typename Element::priority_type,&Element::priority>, std::greater<typename Element::priority_type>  >
        >
    > Elements;

    void insert(const Element& e){
        typename Elements::template index<byseq>::type& list_view = elements.get<byseq>();
        list_view.push_back(e);
    }
    boost::optional<Element> peek() const{  
        boost::optional<Element> res;
        typename Elements::template index<bypriority>::type::iterator it = elements.get<bypriority>().begin();
        if(it != elements.get<bypriority>().end()){
            res.reset(*it);
        }
        return res;
    }
    boost::optional<Element> pop() {
        boost::optional<Element> res;
        typename Elements::template index<bypriority>::type& priority_index = elements.get<bypriority>();
        typename Elements::template index<bypriority>::type::iterator it = elements.get<bypriority>().begin();
        if(it != elements.get<bypriority>().end()){
            res.reset(*it);
            priority_index.erase(it);
        }
        return res;
    }
    void print_in_order(std::ostream& os) const{
        typedef  typename Elements::template index<byseq>::type elements_by_sequence;
        for(typename elements_by_sequence::iterator it = elements.get<0>().begin(); it != elements.get<0>().end(); it++){
            os << *it << std::endl;
        }
    }
    protected:
    Elements elements;
};

using namespace std;
int main(int argc, char *argv[]) {
    Container<MyElement> c;
    c.insert(MyElement("Bob",10));
    c.insert(MyElement("Alice",100));
    c.insert(MyElement("Fred",20));

    c.print_in_order(std::cout);
    cout << endl << "Highest Priority is " << endl << *c.peek() << endl;
    boost::optional<MyElement> alice = c.pop();
    if(alice){
        cout << "Popped results are " << *alice << endl;
    }

    cout << endl << "Now the contents are" << endl;
    c.print_in_order(std::cout);
}

将输出:

Name: Bob Priority: 10
Name: Alice Priority: 100
Name: Fred Priority: 20
Highest Priority is 
Name: Alice Priority: 100
Popped results are Name: Alice Priority: 100
Now the contents are
Name: Bob Priority: 10
Name: Fred Priority: 20