#c #sorting #map #queue #call
#c #сортировка #словарь #очередь #вызов
Вопрос:
теперь у меня есть std::map<std::string, Object> myMap
. Класс Object
имеет функции: int getPriority()
и void Work()
. Теперь я просматриваю карту и хочу вызвать Work
из-за приоритета объекта.
Я написал очень сумасшедшую идею: клонировать эту карту, но она сохраняет в ключе ее приоритет, например:
myMap["3_key1"] = Object();
myMap["6_key2"] = Object();
myMap["0_key3"] = Object();
Он сортирует, и вызов находится в правильной очереди: 0_key3; 3_key1; 6_key2
.
Но я думаю, что это очень медленно. И я хочу заменить std::map
на unordered_map
из boost, потому что это намного быстрее. И здесь нет сортировки по ключу.
Итак, есть идеи?
Комментарии:
1. Могу я спросить, почему вы считаете, что это медленно?
2. И, кроме того, знаете ли вы, какие операции
unordered_map
выполняются быстрее стандартныхmap
?3. @GMan да. @kiril-kirov простая вставка.
Ответ №1:
Используйте Boost.Мультииндекс:
// your class
#include <iostream>
#include <string>
class foo
{
public:
foo(std::string name, unsigned priority, std::string msg) :
mPriority(priority)
{
mName.swap(name); // primitive std::move :)
mMsg.swap(msg); // (default-construct amp; swap)
}
const std::stringamp; name() const
{
return mName;
}
unsigned priority() const
{
return mPriority;
}
void work() const
{
std::cout << mMsg << std::endl;
}
private:
std::string mName;
unsigned mPriority;
std::string mMsg;
};
// your container
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
namespace bmi = boost::multi_index;
typedef boost::multi_index_container<foo,
bmi::indexed_by<
// order by name (std::map)
bmi::ordered_unique<
bmi::const_mem_fun<foo, const std::stringamp;, amp;foo::name>
>,
// order by priority (std::multi_map)
bmi:: ordered_non_unique<
bmi::const_mem_fun<foo, unsigned ,amp;foo::priority>
>
>
> foo_set;
// test
#include <boost/foreach.hpp>
int main()
{
foo_set fooSet;
fooSet.insert(foo("a", 4, "this is a, priority 4"));
fooSet.insert(foo("b", 3, "this is b, priority 3"));
fooSet.insert(foo("c", 7, "this is c, priority 7"));
fooSet.insert(foo("d", 1, "this is c, priority 1"));
// view as map from name to value
foo_set::nth_index<0>::typeamp; nameView = fooSet.get<0>();
nameView.find("a")->work(); // find "a", print its message
if (nameView.find("e") == nameView.end())
std::cerr << "e not found" << std::endl;
std::cout << std::endl;
// view as multi_map from priority to value
foo_set::nth_index<1>::typeamp; priorityView = fooSet.get<1>();
BOOST_FOREACH(const fooamp; f, priorityView)
f.work(); // work, in order of priority
}
У меня нет никаких тестов производительности для этого, но это, безусловно, лучше выражает ваши намерения, и это обычно свидетельствует об улучшении производительности в любом случае.
Комментарии:
1. Отличный ответ. Впрочем, как всегда 🙂
Ответ №2:
Я думаю, что самый простой способ — это два контейнера. Ваша текущая карта ключ-> значение и вторая куча ключей, упорядоченных по приоритету объекта (возможно, просто используйте priority_queue
в качестве вашей реализации кучи). Однако это может вызвать трудности с приоритетом, который может измениться на лету.
Ответ №3:
Если вы используете std::set или std::priority_queue вместо std::map, вы можете определить функтор или просто реализовать operator< для своего класса, чтобы std::set упорядочивал объекты в порядке приоритета для вас.
#include <iostream>
#include <set>
class Object {
public:
int m_priority;
Object(int p) : m_priority(p) { }
int getPriority() const { return m_priority; }
void Work() const { std::cout << m_priority << std::endl; }
};
bool operator<(const Object amp; lhs, const Object amp; rhs)
{
return lhs.getPriority() < rhs.getPriority();
}
int main()
{
std::set<Object> container;
container.insert(Object(1));
container.insert(Object(9));
container.insert(Object(5));
container.insert(Object(8));
container.insert(Object(3));
for (std::set<Object>::iterator I = container.begin();
I != container.end();
I) {
I->Work();
}
}