每次更新时显示地图按值排序

Posted

技术标签:

【中文标题】每次更新时显示地图按值排序【英文标题】:display map every time it is updated sorted by value 【发布时间】:2009-09-29 16:34:12 【问题描述】:

基本上,我有

map<std::string, int>

所以如果我有

富 5 小节 10 插孔 3

在地图中,我要显示它(注意倒序)

小节 10 富 5 插孔 3

每次更新时,我都想遍历所有元素,找出它们,按值排序。实现它的好方法是什么?我应该为构造函数提供一个比较器吗?

我要注意的是,地图中的值将至少更新 1 亿次,因此效率至关重要,而多余的空间也没有问题

请不要使用 Boost 解决方案...谢谢

【问题讨论】:

你说要显示按value排序的map,但是你给出的例子是key排序的。你能澄清一下吗? 你想在每次插入地图时显示内容吗? 是的,每次。好吧,我想按值排序..它也意外地按键排序。 你需要一个更好的例子。我们是否按名称排序,升序;或数字,降序?因为要执行后者,您需要map&lt;int, string&gt; 查看我的回答,为了保持名称的唯一性和按 int 排序,我建议使用 bimap(对于 2-indexes 情况的 Boost MultiIndex 扩展)。 【参考方案1】:
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 以确定键值对,然后更新 map 和 set。在打印时,您只需遍历集合。就理论时间复杂度而言,这是最优的。但是,它使内存加倍。这符合您的目标吗?

为了减少内存,您可以考虑以下几点:

map<std::string,uint64_t>; set<uint64_t>;

映射的值(也是集合的键)是:(uint64_t)val。此解决方案也更快,因为它避免了字符串之间的比较。

【讨论】:

【参考方案2】:

如果您想要一个按键和值排序的高性能映射,您想要Boost MultiIndex,它会在每次更新时更新(重新排序)(您必须手动执行)并且有一个很好的文档。

【讨论】:

实际上,对于地图,您需要 Boost Bimap,它(恕我直言)更易于使用。但这并没有什么神奇之处,它在幕后使用了 Boost MultiIndex。请参阅下面的答案以获取一些代码。【参考方案3】:

前面的回复有不便没有考虑到初始需求(key是std::string,value是int)。

已编辑:在 cmets 之后,我想直接用 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;
  

现在应该更容易理解我的意思了:)

【讨论】:

我认为这个问题准确地处理了这样一个事实,即虽然按键排序,但他希望它们以递减的顺序打印。除了 boost::bimap 的推荐之外,大多数或您的回答在这方面都具有误导性。【参考方案4】:

嗯,你必须按键排序。 “按值排序”的最简单方法是使用切换键和值的多图。所以这是一种方法(注意——我现在无法访问编译器,所以如果它不能编译,我很抱歉):

#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&lt;int&gt; 以降序排序。我们使用的是多图,因此多个名称可以有相同的数字。

struct MapKeyOutput

    void operator()(const MapType::value_type& val)
    
        std::cout << val.second << " " << val.first << "\n";
    

这是一个函数对象,用于输出地图中的一个元素。 second 是在 first 之前输出,所以顺序就是你想要的。

std::for_each(m.begin(), m.end(), MapKeyOutput());

这会将我们的函数对象应用于 m 中的每个元素。

【讨论】:

旁注:这有点复杂,因为相同的名称可以添加两次。如果这是一个严重的问题,我会支持 Matthiew M 的 Boost.Bimap 推荐。 好主意,但是,我将如何将比利增加 1?我不断插入键,将值递增 1。 @Andrei Chikatilo:然后你必须删除元素并重新插入它。 Boost.Bimap IIRC 也解决了这个问题。 不能使用 bimap - 它必须是可逆的 m[S]=1; m[R]=1;哎呀 @pgast- 你错了。你想要bimap&lt; set_of&lt;string&gt;, multiset_of&lt;int&gt; &gt;,它的左视图为map&lt;string, int&gt;,右视图为multimap&lt;int, string&gt;

以上是关于每次更新时显示地图按值排序的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET 在更新面板更新时显示“正在加载...”消息

在 Java 中按值映射自动排序

在更新时显示日志文件的内容

有没有办法在更新列表中的 DOM 时显示 JSON 数据?

更新 React 中删除时显示的组件列表

以编程方式更新桌面“拖动时显示窗口内容”设置