我必须将一组已知整数映射到另一组已知整数,1对1关系,所有预定义等等。所以,假设我有这样的东西(c ++,简化,但你会得到这个想法):
struct s { int a; int b; };
s theMap[] = { {2, 5}, {79, 12958 } };
现在给出一个输入整数,比如79,我需要从Map中找到相应的结果(显然是12958)。任何好的和快速的方法,而不是你的普通循环?其他数据结构建议也是受欢迎的,但地图应该易于手工编写。
两组中的值都在0到2 ^ 16的范围内,并且只有大约130对。我也追求的是一种静态初始化数据的简单方法。
答案 0 :(得分:12)
使用地图
#include <map>
#include <iostream>
int main() {
std::map <int, int> m;
m[79] = 12958;
std::cout << m[79] << std::endl;
}
使用映射是最通用的解决方案,也是最便携的(C ++标准尚不支持散列表,但它们是非常常见的扩展)。尽管如此,这并非必要。二进制搜索和其他人建议的哈希映射解决方案可能(但不会)超出它。但是,对于大多数应用程序而言,这可能无关紧要。
答案 1 :(得分:8)
按键对数组排序并进行二进制搜索。
答案 2 :(得分:7)
如果您需要编译时间映射,可以使用以下模板:
// template to specialize
template<int T> struct int2int {};
// macro for simplifying declaration of specializations
#define I2I_DEF(x, v) template<> struct int2int<x> { static const int value = v; };
// definitions
I2I_DEF(2, 5) I2I_DEF(79, 12958) I2I_DEF(55, 100) // etc.
// use
#include <iostream>
int main()
{
std::cout << int2int<2>::value << " " << int2int<79>::value << std::endl;
return 0;
}
答案 3 :(得分:3)
如果源整数i
的数量相对较高(以便直接搜索效率低下)但仍然可管理,则可以相对轻松地为输入整数构建完美的哈希函数hash(i)
(例如,使用Pearson hashing,然后使用散列值作为输入表map
output = map[hash(i)];
当然,如果输入值的范围相对较小,您可以使用标识函数代替hash
,只需将整个事物转换为直接重新映射
output = map[i];
(尽管如果是这种情况,你甚至不会问。)
答案 4 :(得分:2)
std::map<int, int> theMap;
theMap[2] = 5;
std::map<int, int>::const_iterator iter = theMap.find(2);
if (iter != theMap.end())
iter->second; // found it
插入一对int,按键检索值,对数复杂度。如果你有一个非常大的数据集并且需要更快的检索,请使用std :: tr1 :: unordered_map或boost :: unordered_map(如果你的标准库没有TR1实现)。
答案 5 :(得分:2)
std::map或std::unordered_map可能是最清洁的。不幸的是,C ++没有内置的关联数组。
std::map<int,int> mymap; // the same with unordered map
// one way of inserting
mymap.insert ( std::make_pair(2,5) );
mymap.insert ( std::make_pair(79,12958) );
// another
mymap[2] = 5;
mymap[79] = 12958;
检查
std::map<int,int>::const_iterator iter = mymap.find(2);
if ( iter != mymap.end() )
{
// found
int value = iter->second;
}
unordered_map
的优势在于O(1)
分摊的查询时间,而不是O(log n)
的{{1}}。
答案 6 :(得分:2)
作为补充,如果您需要二进制搜索实现,请不要忽略C ++标准库。以下使用equal_range算法对您的结构类型的数组进行一个处理(对代码的某些hacky质量道歉)
#include <algorithm>
#include <iostream>
using namespace std;
struct S {
int k, v;
};
bool operator <( const S & a, const S & b ) {
return a.k < b.k;
};
// must be sorted in key order
S values[] = {{42,123},{666,27}};
int main() {
S t;
cin >> t.k;
S * valend = &values[0] + sizeof(values) / sizeof(S);
pair <S*,S*> pos = equal_range( &values[0], valend , t);
if ( pos.first != pos.second ) {
cout << pos.first->v << endl;
}
else {
cout << "no" << endl;
}
}
答案 7 :(得分:1)
为什么不是哈希地图?它会为您提供或多或少的任何密钥的检索时间。
答案 8 :(得分:1)
你有正确的想法,这是一张地图。使用std::map。
答案 9 :(得分:1)
跳转表。如果你能够使用它,开关可能会设置它,否则你可能需要一些组装,但这可能是最快的方式。
答案 10 :(得分:1)
您可以使用boost :: assign。
#include <iostream>
#include <boost/assign.hpp>
int main()
{
typedef std::map< int, int > int2int_t;
typedef int2int_t::const_iterator int2int_cit;
const int2int_t theMap
= boost::assign::map_list_of
( 2, 5 )
( 79, 12958 )
;
int2int_cit it = theMap.find( 2 );
if ( it != theMap.end() )
{
const int result = it->second;
std::cout << result << std::endl;
}
}
答案 11 :(得分:0)
如果您100%确定theMap
不会增加到超过1,000个条目(个人资料!),那么进行二分查找可能会更快。
如果a
的值具有合理的界限(例如,低于1,000),则可以使用a
作为保证O(1)复杂度的索引来创建一个简单数组。如果您正在使用gcc,则可以使用此语法(http://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html#Designated-Inits):
int theMap[256] = { [2] = 5, [79] = 12958 };
(遗憾的是,g ++不支持此功能)
在任何其他情况下,请使用std::unordered_map
,如其他答案中所示。
答案 12 :(得分:0)
您的伪代码几乎是有效的C ++ 0x代码 - 但C ++ 0x需要更少!
map<int, int> theMap = { {2, 5}, {79, 12958 } };
assert ( theMap[ 2 ] == 5 );
在“普通”C ++中,你必须像这样初始化地图,仍然非常优雅:
pair< int, int > map_array[2] = { make_pair(2, 5), make_pair(79, 12958) };
map< int, int > theMap( &map_array[0], &map_array[2] ); // sorts the array
assert ( theMap[ 2 ] == 5 );
编写速度快,运行速度快!
编辑:不要让地图成为全局变量。 (虽然这在C ++ 0x中是安全的。)如果这样做,只有在编译器选择在map_array之后初始化它时才会正确初始化,这是非常不能保证的。如果您想成为全局用户,请使用 theMap.assign( &map_array[0], &map_array[2] );
初始化它。
答案 13 :(得分:0)
还有一种称为“xmacros”的技术,这是一种很好的方式来完成你所说的。但是,很容易滥用这项技术,所以我总是建议小心使用它。查看:http://en.wikipedia.org/wiki/C_preprocessor#X-Macros
基本要点是,你有一个文件,你列出你的映射说foo.txt,如下所示:
MAP(2,5)
MAP(79,12958)
...
然后定义一个宏MAP(A,B),它接受这两个参数并为您进行初始化。然后#include文件(foo.txt)。如果您愿意,您甚至可以通过在文件的每个#include之间重新定义宏来进行多次传递。然后添加更多映射,只需将它们添加到foo.txt并重新编译即可。它非常强大,可以用于许多不同的事情。
答案 14 :(得分:0)
如果您不想出于某种原因使用地图(例如,您只想使用在编译时设置的数组),您还可以将functor与{结合使用} {1}}:
<algorithm>