基本上,我有
map<std::string, int>
所以,如果我有
在地图中,我想显示它(注意相反的顺序)
每次更新时,我都希望迭代所有元素,然后按值排序。实现这个的好方法是什么?我应该为构造函数提供比较器吗?
我想注意地图中的值将至少更新1亿次,因此效率至关重要,因为额外空间没有问题
请不要提升解决方案... thx
答案 0 :(得分:2)
如果你想要一个按键和值排序的高性能地图,你需要Boost MultiIndex,它会在每次更新时(你必须手动完成)更新(使用)并且有一个很好的文档。
答案 1 :(得分:2)
struct keyval_t { std::string key; int val; };
int operator<(const keyval_t &a, const ketval_t &b)
{ return a.val<b.val || (a.val==b.val && a.key<b.key); }
然后你需要一张地图和一套:
map<std::string, int>; set<keyval_t>;
在更新时,您需要先查找地图以确定键值对,然后更新地图和集。在打印时,您只需遍历该集。就理论时间复杂度而言,这是最佳的。然而,它使记忆增加了一倍。这符合你的目标吗?
要减少记忆,您可以考虑以下事项:
map<std::string,uint64_t>; set<uint64_t>;
映射的值(也是集合的键)是:(uint64_t)val&lt;&lt; 32 | counter,其中counter是区分相同值的东西。例如,无论何时插入密钥,都将计数器增加1.更新值时无需更新计数器。如果您不喜欢uint64_t,请使用pair&lt; int,int&gt;代替。此解决方案也更快,因为它避免了字符串之间的比较。
答案 2 :(得分:1)
以前的回复不便不考虑初始要求(键是std :: string,值是int)。
编辑:在评论之后,我想直接用Bimap呈现它更好:)
所以我们走了,就在这里!
#include <boost/bimap.hpp>
class MyMap
{
struct name {};
struct value {};
typedef boost::tagged<name, std::string> tagged_name;
typedef boost::tagged<value, int> tagged_value;
// unordered_set_of: guarantees only unicity (not order)
// multi_set_of: guarantees only order (not unicity)
typedef boost::bimap< boost::unordered_set_of< tagged_name >,
boost::multi_set_of< tagged_value,
std::greater< tagged_value >
>
> impl_type;
public:
// Redefine all usual types here
typedef typename impl_type::map_by<name>::const_iterator const_iterator;
typedef typename impl_type::value_type value_type;
// Define the functions you want
// the bimap will not allow mutators because the elements are used as keys
// so you may want to add wrappers
std::pair< iterator, bool > insert(const value_type & x)
{
std::pair< iterator, bool > result = m_impl.insert(x);
if (result.second) this->display();
return result;
} // insert
iterator insert(iterator position, const value_type & x)
{
iterator result = m_impl.insert(x);
this->display();
return result;
} // insert
template< class InputIterator >
void insert(InputIterator first, InputIterator last)
{
m_impl.insert(first, last);
this->display();
} // insert
private:
void display() const
{
// Yeah I know about std::for_each...
typedef typename impl_type::map_by<value>::const_iterator const_it;
for (const_it it = m_impl.begin(), end = m_impl.end(); it != end; ++it)
{
// Note the inversion of the 'second' and 'first',
// we are looking at it from the right
std::cout << it->second << " " << it->first << std::endl;
}
}
impl_type m_impl;
}; // class MyMap
你走了。
我强烈建议您查阅bimap文档。存储有很多可能性(set_of,unordered_set_of,unconstrained_set_of,muli变体,list_of变体......)所以可能有一个可以做你想做的事。
然后您还可以在每次显示时进行排序:
#include <set>
#include <map>
// Just use a simple std::map<std::string,int> for your impl_type
// Mutators are allowed since the elements are sorted each time you display
struct Comparator
{
bool operator(const value_type& lhs, const value_type& rhs) const
{
return lhs.second < rhs.value;
}
};
void display() const
{
typedef std::multi_set<value_type, Comparator> sort_type;
sort_type mySet;
std::copy(m_impl.begin(), m_impl.end(), std::inserter(mySet, mySet.end()));
for (sort_type it = mySet.begin(), end = mySet.end(); it != end; ++it)
{
std::cout << it->first<< " " << it->second << std::endl;
}
}
现在应该更容易理解我的观点:)
答案 3 :(得分:0)
嗯,你必须按键排序。 “按值排序”的最简单方法是使用带有键和值切换的多图。所以这是一种方法(注意 - 我现在无法访问编译器,所以如果它不编译,我很抱歉):
#include <algorithm>
#include <functional>
#include <map>
#include <string>
#include <utility>
typedef std::multimap<int, std::string, std::greater<int> > MapType;
struct MapKeyOutput
{
void operator()(const MapType::value_type& val)
{
std::cout << val.second << " " << val.first << "\n";
}
}
void display_insert(MapType& m, const std::string& str, int val)
{
m.insert(std::make_pair(val, str));
std::for_each(m.begin(), m.end(), MapKeyOutput());
}
int main()
{
MapType m;
display_insert(m, "Billy", 5);
display_insert(m, "Johnny", 10);
}
你也可以制作一个内部使用多图的地图类,我只是不想输出它。然后display_insert将成为一些成员函数。不过,这应该证明了这一点。兴趣点:
typedef std::multimap<int, std::string, std::greater<int> > MapType;
请注意,比较器为greater<int>
以降序排序。我们正在使用多图,因此多个名称可以具有相同的数字。
struct MapKeyOutput
{
void operator()(const MapType::value_type& val)
{
std::cout << val.second << " " << val.first << "\n";
}
}
这是一个在地图中输出一个元素的函数对象。第二个在第一个之前输出,所以订单就是你想要的。
std::for_each(m.begin(), m.end(), MapKeyOutput());
这将我们的函数对象应用于m。
中的每个元素