【问题标题】:Reverse map lookup反向地图查找
【发布时间】:2011-04-21 19:50:33
【问题描述】:

我有一张一对一的地图。从值中查找键的最佳方法是什么,

例如,如果地图是这样的

关键值

a    1
b    2
c    3 
d    4

我希望能够找到3对应的键是C。

谢谢!

【问题讨论】:

    标签: c++ stl map


    【解决方案1】:

    您对此无能为力。您可以选择使用两张地图,使用来自Boost Multi-Index 库的多键地图,或者进行线性搜索。

    更新:最轻量级的开箱即用解决方案似乎是Boost.Bimap,它代表双向地图。

    【讨论】:

      【解决方案2】:

      假设你有一张地图<X,Y>。构建第二个结构,可能是 map<Y*,X*,Deref>,它启用反向查找但避免将存储开销加倍,因为使用指针,无需将每个 X 和 Y 存储两次。第二个结构只是有指向第一个的指针。

      【讨论】:

      • 每个指针通常占用 4-8 个字节。仅当指针比对象轻并且取消引用的成本可以忽略不计时才使用它。删除map<X,Y> 中的条目时也要小心,因为指针无效。
      【解决方案3】:

      最直接的方法是维护一个并行映射,其中值和键是相反的(因为关系是一对一的)。

      【讨论】:

        【解决方案4】:

        另一种解决方案是使用(鲜为人知的?)Boost.Bimap:

        Boost.Bimap 是一个双向映射 C++ 库。使用 Boost.Bimap 你 可以在 这两种类型都可以用作键。一种 bimap<X,Y> 可以认为是 std::map<X,Y>std::map<Y,X>。学习曲线 如果你知道怎么做,bimap 几乎是平的 使用标准容器。一个伟大的 已经付出了很多努力 映射 STL 的命名方案 在 Boost.Bimap 中。图书馆是 旨在匹配常见的 STL 容器。

        【讨论】:

          【解决方案5】:

          给定一个从键到值的std::map,以下函数将返回一个反向查找表,一个从值到键的std::map

              /// Given a map from keys to values, creates a new map from values to keys 
              template<typename K, typename V>
              static map<V, K> reverse_map(const map<K, V>& m) {
                  map<V, K> r;
                  for (const auto& kv : m)
                      r[kv.second] = kv.first;
                  return r;
              }
          

          【讨论】:

            【解决方案6】:

            除非地图很大,或者你有其他方式知道线性搜索太慢,否则我会从线性搜索开始:

            #include <iostream>
            using std::cout;
            
            #include <map>
            using std::map;
            
            #include <algorithm>
            using std::find_if;
            
            #include <boost/assign/list_of.hpp>
            using boost::assign::map_list_of;
            
            typedef map<char, int> Map;
            typedef Map::key_type Key;
            typedef Map::value_type Pair;
            typedef Map::mapped_type Value;
            
            
            struct finder {
                const Value v;
                finder(const Value& v) : v(v) {}
                bool operator()(const Pair& p) {
                    return p.second == v;
                }
            };
            
            Map m = map_list_of('a', 1)('b', 2)('c', 3)('d', 4)('e', 5);
            
            int main() {
                Pair v = *find_if(m.begin(), m.end(), finder(3));
                cout << v.second << "->" << v.first << "\n";
            }
            

            【讨论】:

            • 在使用其他语言 20 多年后,我最近重新开始使用 C++,所以我有点生疏了。有没有办法将 finder 实现为内联 lambda 函数/表达式?
            【解决方案7】:

            @Robᵩ 上面使用 lambda 的答案的变体:

            map<char, int> m = {{'a', 1}, {'b', 2}, {'c', 3}, {'d', 4}, {'e', 5}};
            
            int findVal = 3;
            auto it = find_if(m.begin(), m.end(), [findVal](const Pair & p) {
                return p.second == findVal;
            });
            if (it == m.end()) {
                /*value not found*/
                cout << "*value not found*";
            }
            else {
                Pair v = *it;
                cout << v.second << "->" << v.first << "\n";
            }
            

            (感谢@Nawaz 在这里的贡献:https://stackoverflow.com/a/19828596/1650814

            【讨论】:

              【解决方案8】:

              我知道这是一个很老的问题,但这篇 codeproject 文章 (http://www.codeproject.com/Articles/3016/An-STL-like-bidirectional-map) 是双向映射的一个很好的例子。

              这是一个示例程序,展示了它是多么容易:

               #pragma warning(disable:4503)
              
                  #include "bimap.h"
                  #include <iostream>
                  #include <string>
              
                  using codeproject::bimap;
              
                  int main(void)
                  {
                    bimap<int,std::string> bm;
              
                    bm[1]="Monday";
                    bm[2]="Tuesday";
                    bm[3]="Wednesday";
                    bm[4]="Thursday";
                    bm[5]="Friday";
                    bm[6]="Saturday";
                    bm[7]="Sunday";
              
                    std::cout<<"Thursday occupies place #"<<bm["Thursday"]<<
                               " in the week (european style)"<<std::endl;
                    return 0;
                  }
              

              【讨论】:

                猜你喜欢
                • 2012-05-23
                • 1970-01-01
                • 2020-03-09
                • 1970-01-01
                • 2011-10-01
                • 2014-02-16
                • 2014-04-06
                • 1970-01-01
                • 2011-04-07
                相关资源
                最近更新 更多