在C ++映射中,有没有办法搜索给定值的键?

时间:2014-01-07 19:48:24

标签: c++

在C ++ std::map中,有没有办法在给定映射值的情况下搜索密钥?例如:

我有这张地图:

map<int,string> myMap;
myMap[0] = "foo";

在给定值int的情况下,有什么方法可以找到相应的"foo"吗?

cout << myMap.some_function("foo") <<endl;

Output: 0

5 个答案:

答案 0 :(得分:5)

std::map没有提供(快速)方法来查找给定值的键。

你想要的通常被称为“双射地图”,或简称为“bimap”。 Boost has such a data structure.这通常通过使用两个“粘合”在一起的索引树来实现(其中std::map只有一个用于键)。 Boost also provides the more general multi index with similar use cases.

如果您不想使用Boost,如果存储不是一个大问题,并且您可以使用额外的代码工作,您可以简单地使用两个地图并将它们手动粘合在一起:

std::map<int, string> myMapForward;
std::map<string, int> myMapBackward;    // maybe even std::set

// insertion becomes:
myMapForward.insert(std::make_pair(0, "foo"));
myMapBackward.insert(std::make_pair("foo", 0));

// forward lookup becomes:
myMapForwar[0];

// backward lookup becomes:
myMapBackward["foo"];

当然,您可以将这两个地图包装在一个类中并提供一些有用的界面,但这可能有点过分,并且使用两个具有相同内容的地图无论如何都不是可选的解决方案。如下所述,异常安全性也是该解决方案的问题。但在许多应用程序中,只需添加另一个反向映射即可。

请注意,由于std::map存储了唯一键,因此此方法仅支持唯一值的后向查找,因为前向的值空间中存在冲突map对应于后向映射的键空间中的碰撞。

答案 1 :(得分:2)

不,不是直接。

一种选择是检查地图中的每个值,直到找到您要查找的内容。显然,这将是O(n)。

为了做到这一点,你可以写一个for()循环,或者你可以使用std::find_if()。要使用find_if(),您需要创建谓词。在C ++ 11中,这可能是一个lambda:

typedef std::map <unsigned, Student> MyMap;
MyMap myMap; 

// ...

const string targetName = "Jones";
find_if (myMap.begin(), myMap.end(), [&targetName] (const MyMap::value_type& test)
{
  if (test.second.mName == targetName)
    return true;
});

如果您使用的是C ++ 03,那么这可能是一个仿函数:

struct MatchName
: public std::unary_function <bool, MyMap::value_type>
{
  MatchName (const std::string& target) : mTarget (target) {}
  bool operator() (const MyMap::value_type& test) const
  {
    if (test.second.mName == mTarget)
      return true;
    return false;
  }
private:
  const std::string mTarget;
};


// ...

find_if (myMap.begin(), myMap.end(), MatchName (target));

另一种选择是建立一个索引。索引可能是另一个映射,其中键是您要查找的任何值,值是返回主映射的某种索引。

假设您的主地图包含Student个对象,其中包含名称和其他内容,此地图中的关键字是学生ID,即整数。如果要查找具有特定姓氏的学生,可以构建索引映射,其中键是姓(可能希望在此使用multimap),值为学生ID。然后,您可以回溯到主地图以获取Student的其余属性。

第二种方法存在挑战。添加或删除元素时,必须使主映射和索引(或指标)保持同步。您必须确保您选择的索引作为索引中的值不是可能更改的内容,如指针。如果你是多线程的,那么你必须考虑如何在不引入死锁或竞争条件的情况下保护地图和索引。

答案 2 :(得分:0)

我能想到的实现这一目标的唯一方法是迭代它。这很可能不是你想要的,但它是我能想到的最佳镜头。祝你好运!

答案 3 :(得分:0)

您可以通过迭代来实现这一目标,这将花费O(n) time。或者您可以存储反向地图,这将采用O(n) space

通过迭代:

std::map<int, string> fmap;

for (std::map<int,string>::iterator it=fmap.begin(); it!=fmap.end(); ++it)
    if (strcmp(it->second,"foo"))
        break;

存储反向地图:

std::map<int, string> fmap;
std::map<string, int> bmap;

fmap.insert(std::make_pair(0, "foo"));
bmap.insert(std::make_pair("foo", 0));

fmap[0]; // original map lookup

bmap["foo"]; //reverse map lookup

答案 4 :(得分:0)

不,你不能这样做。您只需迭代map并将每个值与要匹配的项匹配并返回相应的键,这将花费您高时间复杂度等于O(n)。