Обратный поиск по карте - PullRequest
40 голосов
/ 21 апреля 2011

У меня есть карта 1 к 1. Какой лучший способ найти ключи от значений,

т.е.

Например, если карта такая

КЛЮЧЕВОЕ ЗНАЧЕНИЕ

a    1
b    2
c    3 
d    4

Я хочу найти ключ, соответствующий 3, это C.

Спасибо!

Ответы [ 8 ]

30 голосов
/ 21 апреля 2011

Вы ничего не можете с этим поделать. У вас есть возможность работать с двумя картами, использовать многоключевую карту, например одну из библиотеки Boost Multi-Index , или выполнять линейный поиск.

ОБНОВЛЕНИЕ: Наиболее легким из готовых решений является Boost.Bimap , что означает двунаправленную карту.

12 голосов
/ 03 июня 2012

Скажем, у вас есть карта <X,Y>.Создайте вторую структуру, возможно, карту <Y*,X*,Deref>, которая обеспечивает обратный поиск, но избегает удвоения накладных расходов на хранение, потому что, используя указатели, нет необходимости хранить каждый X и Y дважды.Вторая структура просто имеет указатели на первую.

8 голосов
/ 21 апреля 2011

Наиболее прямым способом было бы поддерживать параллельную карту, где значения и ключи меняются местами (поскольку взаимосвязь один к одному).

6 голосов
/ 22 апреля 2011

Другое решение будет использовать (менее известный?) Boost.Bimap :

Boost.Bimap - это двунаправленные карты библиотека для C ++. С Boost.Bimap вы может создавать ассоциативные контейнеры в которые оба типа могут быть использованы в качестве ключа. bimap<X,Y> можно рассматривать как комбинация std::map<X,Y> и std::map<Y,X>. Кривая обучения Бимап почти плоский, если вы знаете, как использовать стандартные контейнеры. Великий много усилий было вложено в отображение схемы именования STL в Boost.Bimap. Библиотека разработан, чтобы соответствовать общему стандарту STL контейнеры.

4 голосов
/ 22 апреля 2011

Если карта не огромная или у вас нет другого способа узнать, что линейный поиск слишком медленный, я бы начал с линейного поиска:

#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";
}
3 голосов
/ 07 ноября 2013

Вариант ответа @ Робо выше, который использует лямбду:

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)

2 голосов
/ 09 октября 2014

Я знаю, что это действительно старый вопрос, но эта статья о проекте кода (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;
    }
1 голос
/ 24 декабря 2018

Учитывая 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;
    }
...