Расширенная очередь с приоритетом

Я ищу реализацию приоритетной очереди в C++. Помимо базовой функциональности в приоритетной очереди STL требуются следующие методы:

  1. Он может удалять все одинаковые элементы (определяемые функцией) при нажатии (аналогично набору)
  2. Он может отфильтровывать некоторые элементы (определяемые другой функцией).

Есть ли у вас какие-либо предложения о том, как это реализовать?


person Tianyi Liang    schedule 18.10.2012    source источник
comment
Я не вижу необходимости отрицать этот вопрос, это законный вопрос.   -  person πάντα ῥεῖ    schedule 18.10.2012
comment
Не могли бы вы расширить фильтрацию? Вы имеете в виду предотвращение попадания элементов в очередь или возможность применить фильтр к существующей очереди (и, следовательно, возможно, несколько разных фильтров за время существования очереди).   -  person Matthieu M.    schedule 18.10.2012
comment
Для удаления повторяющихся элементов я думаю использовать std::priority_queue‹ T*, std::set‹ T*, dup_predicate ›, cmp_predicate ›. Для фильтрации я имею в виду, что если я передам предикат фильтра, все удовлетворяющие элементы будут удалены.   -  person Tianyi Liang    schedule 18.10.2012


Ответы (2)


Вы можете использовать std::set в качестве приоритетной очереди без дубликатов. Элемент top можно найти через rbegin(). Асимптотическая сложность такая же, как и для двоичной кучи: O(1) top в соответствии со стандартными требованиями для rbegin, O(lg n) push и O(lg n) pop . Однако константы будут выше.

Что касается фильтра, я предлагаю вам обернуть std::set в класс с помощью пользовательского метода push (что в любом случае является хорошей идеей), который запускает предикат фильтрации для вас.

person Fred Foo    schedule 18.10.2012
comment
@KarolyHorvath std::set также гарантирует строгий порядок своих элементов. Пока элементы обеспечивают соответствующую операцию std::less со ссылкой на их индикатор приоритета, и вы хотите, чтобы там были только уникальные элементы (о которых, по-видимому, просит OP), это должно работать. - person πάντα ῥεῖ; 18.10.2012
comment
Однако есть одна проблема: для уникальности и приоритета могут потребоваться разные предикаты. - person Matthieu M.; 18.10.2012
comment
Мне нравится эта идея. У меня есть еще один вопрос. Могу ли я использовать std::priority_queue‹ T*, std::set‹ T* ›, cmp_predicate ›? И я пытаюсь сделать фильтрацию внутри. Но я не знаю, как получить доступ к его внутренней структуре данных. - person Tianyi Liang; 18.10.2012
comment
@TianyiLiang: нет. std::set не предлагает правильный интерфейс для включения в std::priority_queue. И вам не нужно обращаться к внутренностям std::set, чтобы выполнять фильтрацию, если вы его обернете. - person Fred Foo; 18.10.2012

Просто оберните priority_queue:

#include <set>
#include <queue>

// Default predicate allows all objects through
template <typename T>
struct allow_any {
    bool operator()(T const&) const {
        return true;
    }
};

// F is a callable type for the filtering predicate -- either a
// function pointer, or a class having an operator()(T const&).
template <typename T, typename F = allow_any<T> >
class filtering_priority_queue {
public:
    explicit filtering_priority_queue(F f) : allow(f) {}

    void push(T x) {
        if (allow(x) && s.find(x) == s.end()) {
            q.push(x);
            s.insert(x);
        }
    }

    T const& top() const {
        return q.top();
    }

    void pop() {
        s.erase(top());
        q.pop();
    }

private:
    std::set<T> s;
    std::priority_queue<T> q;
    F allow;
};
person j_random_hacker    schedule 18.10.2012
comment
Для объектов с идентичностью может быть целесообразно не требовать копии (std::priority_queue<T*, ...>). - person Matthieu M.; 18.10.2012
comment
@MatthieuM.: Мне, вероятно, следует использовать push(T const& x), поскольку top() возвращает константную ссылку, но пользователь должен создавать экземпляр с T* вместо T, если он хочет priority_queue<T*> внизу. - person j_random_hacker; 18.10.2012
comment
Спасибо за ваш комментарий. Однако сделать фильтрацию сложно. Я имею в виду, что если я передал предикат, все удовлетворяющие элементы будут отфильтрованы. В std::priority такая операция не разрешена. - person Tianyi Liang; 18.10.2012
comment
@TianyiLiang: я не понимаю, извините. Проблема в том, что ваш предикат фильтрации возвращает true, когда элемент следует исключить? Просто поменяйте местами true и false или используйте std::logical_not(). - person j_random_hacker; 18.10.2012
comment
На самом деле это подход, который я имел в виду в первую очередь, но его операции будут медленнее, чем мое последнее предложение (за исключением top, который будет немного быстрее). - person Fred Foo; 18.10.2012