数据结构具有相同的堆和映射功率

时间:2013-02-28 15:58:18

标签: c++ algorithm sorting data-structures heap

我想设计一个元素E的容器C.

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

我希望尽可能有效地支持对此容器C的以下操作。

  1. insert: - 将element1(name1,priority1)插入容器: C.insert(element(name1,priority1))
  2. 更新: - 将name = name1的元素的优先级更新为priorityNew1: C [name1] = priorityNew1
  3. delete:-deletes name = name1:C.delete(name1)
  4. 的元素
  5. 获取并删除具有最高优先级的元素:C.pop()
  6. 获取具有最高优先级的元素:C.peek()
  7. 基本上我想要地图和堆的组合。映射元素的'name',并堆积元素的'priority'。 最理想的是我希望每个操作都是O(1)。 否则插入,更新,删除为O(log N)并弹出并查看为O(1)也没关系。

    我可以想到以下两种方法

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

    2)将SQLite与表'element'一起使用,其中包含两列'name'和'priority'。 运行时间将基于SQLite实现。

    我有兴趣了解有关此问题的更多想法,我正面临与此相关的现实世界问题。 感谢您的投入。

2 个答案:

答案 0 :(得分:2)

我不知道Boost是否适合你,但我会查看Boost Mutli Index。 http://www.boost.org/doc/libs/1_53_0/libs/multi_index/doc/index.html

您可以在索引中保留优先级,以便快速获取并插入元素。我类似地使用了boost mutli索引用于MRU / LRU情况。

#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

答案 1 :(得分:2)

如果每个操作的O(logN)都可以接受,显然boost::bimap就足够了。这类似于双面 std::map。通过将两个std::map保持在一起或编写自己的包装器可以得到几乎相同的结果(但为什么要这样做?)。具有自平衡的二叉搜索树具有O(logN)用于最小化检索,其效率略低于堆。

如果效率非常重要,那么您应该使用堆和哈希映射来实现自己的容器。然后,当您在堆中交换时,在哈希映射中维护堆中的name到堆中的预订。这为O(logN)中的O(1)和最小/最大优先级元素提供了插入,删除,重新分配优先级。 (这不是一块蛋糕,但也不乏味)