![](/img/trans.png)
[英]Is there an elegant and fast way to test for the 1-bits in an integer to be in a contiguous region?
[英]Fast and elegant one-way mapping of known integer values
我必須將一組已知整數映射到另一組已知整數,一對一關系,所有預定義等等。 所以,假設我有這樣的東西(c ++,簡化了,但是你會明白的):
struct s { int a; int b; };
s theMap[] = { {2, 5}, {79, 12958 } };
現在給定一個輸入整數,例如79,我需要從Map中找到相應的結果(顯然是12958)。 有什么不錯而又快速的方法來代替循環運行嗎? 也歡迎其他數據結構建議,但該地圖應易於在源代碼中手工編寫。
兩組中的值都在0到2 ^ 16的范圍內,並且只有大約130對。 我還想要的是一種非常簡單的靜態初始化數據的方法。
使用地圖
#include <map>
#include <iostream>
int main() {
std::map <int, int> m;
m[79] = 12958;
std::cout << m[79] << std::endl;
}
使用映射是最通用的解決方案,也是最可移植的(C ++標准尚不支持哈希表,但它們是非常常見的擴展)。 它不一定是最快的。 其他人建議的二進制搜索和哈希圖解決方案都可能(但不會)勝過它。 但是,這對於大多數應用程序可能並不重要。
按鍵對數組進行排序,然后執行二進制搜索。
如果需要編譯時映射,則可以使用以下模板:
// 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;
}
如果您的源整數i
數量相對較高(因此直接搜索變得效率低下)但仍可管理,則可以相對輕松地為輸入整數構建完美的哈希函數hash(i)
(例如,使用Pearson哈希 ),並且然后使用哈希值作為輸出表map
的條目
output = map[hash(i)];
當然,如果輸入值的范圍相對較小,則可以使用恆等函數代替hash
而只需將整個對象變成直接重映射
output = map[i];
(盡管是這種情況,您甚至都不會問。)
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
插入整數對,按鍵,對數復雜度檢索值。 如果您的數據集非常大並且需要更快的檢索速度,請使用std :: tr1 :: unordered_map或boost :: unordered_map(以防您的標准庫沒有TR1實現)。
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;
}
與map
O(log n)
相比, unordered_map
具有O(1)
攤銷查找時間的優勢。
作為補充,如果您需要二進制搜索實現,請不要忽略C ++標准庫。 下面的代碼使用equal_range算法對結構類型的數組執行一個操作(為代碼質量有些怪異而道歉)
#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;
}
}
為什么不使用哈希圖? 它將為您提供或多或少的恆定檢索時間。
您有正確的想法,這是一張地圖。 使用std :: map 。
跳轉表。 如果您能夠使用交換機,則可能會進行設置,否則可能需要進行一些組裝,但這可能是最快的方法。
您可以使用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;
}
}
如果您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
,如其他答案所示。
您的偽代碼幾乎是有效的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] );
對其進行初始化theMap.assign( &map_array[0], &map_array[2] );
。
還有一種稱為“ xmacros”的技術,它也是一種很好的方法,可以准確地完成您正在談論的內容。 但是,很容易濫用該技術,因此我總是建議謹慎使用它。 檢出: http : //en.wikipedia.org/wiki/C_preprocessor#X-Macros
基本要點是,您有一個文件,其中列出了映射文件foo.txt,如下所示:MAP(2,5)
地圖(79,12958)
...
然后,定義一個宏MAP(A,B),它接受這兩個參數並為您進行初始化。 然后#include文件(foo.txt)。 如果您願意,甚至可以通過在文件的每個#include之間重新定義宏來進行多次遍歷。 然后,要添加更多映射,只需將它們添加到foo.txt並重新編譯。 它非常強大,可以用於許多不同的事物。
如果出於某種原因不想使用映射(例如,您只想使用在編譯時設置的數組),則還可以將函子與<algorithm>
結合使用:
#include <windows.h>
#include <cstdlib>
#include <functional>
#include <algorithm>
#include <iostream>
using namespace std;
struct s { int a; int b; };
s theMap[] = { {2, 5}, {79, 12958 } };
struct match_key : public unary_function<s, bool>
{
match_key(int key) : key_(key) {};
bool operator()(const s& rhs) const
{
return rhs.a == key_;
}
private:
int key_;
};
int main()
{
size_t mapSize = sizeof(theMap)/sizeof(theMap[0]);
s* it = find_if(&theMap[0], &theMap[mapSize], match_key(79));
cout << it->b;
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.