我现在有一个std::map<std::string,int>
存储整数值到一个唯一的字符串的标识符,并且我查找与该字符串。 它主要是我想要的,除了它不跟踪的插入顺序。 所以,当我迭代地图打印出来的价值观,他们根据字符串进行排序; 但我希望他们能够根据(第一)插入的顺序进行排序。
我想过使用vector<pair<string,int>>
代替,但我需要查找字符串和增加约1000万次的整数值,所以我不知道是否std::vector
会显著慢。
有没有办法使用方式std::map
或者是有其他std
的容器,更适合我的需要?
[我在GCC 3.4,我有可能不超过50值对我std::map
。
谢谢。
Answer 1:
如果你只有50性病值::地图,你可以在打印之前并通过性病排序将它们复制到标准::矢量::排序使用适当的仿函数。
或者你可以使用的boost :: multi_index 。 它允许使用几个指标。 在你的情况下,它可能看起来像以下:
struct value_t {
string s;
int i;
};
struct string_tag {};
typedef multi_index_container<
value_t,
indexed_by<
random_access<>, // this index represents insertion order
hashed_unique< tag<string_tag>, member<value_t, string, &value_t::s> >
>
> values_t;
Answer 2:
你可能结合了std::vector
用std::tr1::unordered_map
(哈希表)。 这里有一个链接Boost的文档的unordered_map
。 您可以使用矢量跟踪的插入顺序和哈希表做频繁查找的。 如果你正在做几十万的查找,-O之间的差异(log n)的查找了std::map
和O(1)对于一个哈希表可能是显著。
std::vector<std::string> insertOrder;
std::tr1::unordered_map<std::string, long> myTable;
// Initialize the hash table and record insert order.
myTable["foo"] = 0;
insertOrder.push_back("foo");
myTable["bar"] = 0;
insertOrder.push_back("bar");
myTable["baz"] = 0;
insertOrder.push_back("baz");
/* Increment things in myTable 100000 times */
// Print the final results.
for (int i = 0; i < insertOrder.size(); ++i)
{
const std::string &s = insertOrder[i];
std::cout << s << ' ' << myTable[s] << '\n';
}
Answer 3:
保持平行list<string> insertionOrder
。
当需要打印,重复就行了,做查找到地图 。
each element in insertionOrder // walks in insertionOrder..
print map[ element ].second // but lookup is in map
Answer 4:
Tessil已下令地图(和组),这是MIT许可的一个非常好的implementaion。 你可以在这里找到它: 有序地图
例如地图
#include <iostream>
#include <string>
#include <cstdlib>
#include "ordered_map.h"
int main() {
tsl::ordered_map<char, int> map = {{'d', 1}, {'a', 2}, {'g', 3}};
map.insert({'b', 4});
map['h'] = 5;
map['e'] = 6;
map.erase('a');
// {d, 1} {g, 3} {b, 4} {h, 5} {e, 6}
for(const auto& key_value : map) {
std::cout << "{" << key_value.first << ", " << key_value.second << "}" << std::endl;
}
map.unordered_erase('b');
// Break order: {d, 1} {g, 3} {e, 6} {h, 5}
for(const auto& key_value : map) {
std::cout << "{" << key_value.first << ", " << key_value.second << "}" << std::endl;
}
}
Answer 5:
如果你既需要查找的策略,你将最终获得两个容器。 您可以使用vector
与实际值( int
S),并把map< string, vector< T >::difference_type>
旁边,返回索引到载体。
要完成这一切,你可以在一个类中同时封装。
但我相信升压具有容器多个指标。
Answer 6:
你不能做到这一点与地图,但你可以使用两个独立的结构 - 地图和矢量和保持同步 - 那就是当你从地图上删除,查找并从载体中删除的元素。 或者你可以创建一个map<string, pair<int,int>>
-和你对)存储大小(在插入地图的记录位置,与整型值一起,然后在打印时,使用位置构件进行排序。
Answer 7:
这在一定程度上关系到Faisals答案。 你可以创建周边的地图和矢量一个包装类,轻松地保持同步。 适当的封装可以让你控制的访问方法,因此要使用的容器......载体或地图。 这避免了使用升压或类似的东西。
Answer 8:
实现这个另一种方法是用一个map
,而不是一个vector
。 我会告诉你这种方法,并讨论了差异:
只需创建一个具有幕后两张地图的一类。
#include <map>
#include <string>
using namespace std;
class SpecialMap {
// usual stuff...
private:
int counter_;
map<int, string> insertion_order_;
map<string, int> data_;
};
然后,您可以暴露一个迭代器迭代器来data_
以正确的顺序。 你这样做的方式是通过迭代insertion_order_
,并为您从迭代得到每一个元素,做一个查找在data_
从价值insertion_order_
您可以使用更高效hash_map
为insertion_order因为你不关心直接通过迭代insertion_order_
。
要做到插入,你可以有这样的方法:
void SpecialMap::Insert(const string& key, int value) {
// This may be an over simplification... You ought to check
// if you are overwriting a value in data_ so that you can update
// insertion_order_ accordingly
insertion_order_[counter_++] = key;
data_[key] = value;
}
有很多的方法可以使设计更好,担心性能,但是这是一个很好的框架,让你开始了解如何在自己的这个功能。 你可以把它模板,你可能实际存储对作为值data_中,这样就可以很容易地引用insertion_order_的条目。 但我离开这些设计问题作为练习:-)。
更新 :我想我应该说些什么关于使用地图与用于insertion_order_载体的效率
- 查找直接进入数据,在这两种情况下是O(1)
- 在载体中的方法是插入O(1),在地图的方法插入件是O(logn)时间
- 删除向量的方法是为O(n),因为你要扫描的项目删除。 随着地图的方式他们是O(LOGN)。
也许,如果你不打算使用删除尽可能多的,你应该用向量方法。 地图的方法会更好,如果你是支持,而不是插入顺序不同的排序(如优先级)。
Answer 9:
//应该是这样的人!
//这保持了插入的复杂度为O(logN)的和缺失也O(logn)时间。
class SpecialMap {
private:
int counter_;
map<int, string> insertion_order_;
map<string, int> insertion_order_reverse_look_up; // <- for fast delete
map<string, Data> data_;
};
Answer 10:
你想要的(而不是诉诸升压)什么是我所说的“有序散”,这基本上是一个哈希的混搭,用字符串或整数键链表(或两者在同一时间)。 有序散列与散列的绝对性能迭代期间保持元素的顺序。
我已经组建了一个相对较新的C ++代码片段库,在我的视图,用于C ++库开发的C ++语言的孔填充。 到这里:
https://github.com/cubiclesoft/cross-platform-cpp
抓:
templates/detachable_ordered_hash.cpp
templates/detachable_ordered_hash.h
templates/detachable_ordered_hash_util.h
如果用户控制数据将被放置到哈希,您可能还需要:
security/security_csprng.cpp
security/security_csprng.h
调用它:
#include "templates/detachable_ordered_hash.h"
...
// The 47 is the nearest prime to a power of two
// that is close to your data size.
//
// If your brain hurts, just use the lookup table
// in 'detachable_ordered_hash.cpp'.
//
// If you don't care about some minimal memory thrashing,
// just use a value of 3. It'll auto-resize itself.
int y;
CubicleSoft::OrderedHash<int> TempHash(47);
// If you need a secure hash (many hashes are vulnerable
// to DoS attacks), pass in two randomly selected 64-bit
// integer keys. Construct with CSPRNG.
// CubicleSoft::OrderedHash<int> TempHash(47, Key1, Key2);
CubicleSoft::OrderedHashNode<int> *Node;
...
// Push() for string keys takes a pointer to the string,
// its length, and the value to store. The new node is
// pushed onto the end of the linked list and wherever it
// goes in the hash.
y = 80;
TempHash.Push("key1", 5, y++);
TempHash.Push("key22", 6, y++);
TempHash.Push("key3", 5, y++);
// Adding an integer key into the same hash just for kicks.
TempHash.Push(12345, y++);
...
// Finding a node and modifying its value.
Node = TempHash.Find("key1", 5);
Node->Value = y++;
...
Node = TempHash.FirstList();
while (Node != NULL)
{
if (Node->GetStrKey()) printf("%s => %d\n", Node->GetStrKey(), Node->Value);
else printf("%d => %d\n", (int)Node->GetIntKey(), Node->Value);
Node = Node->NextList();
}
我碰到了我在研究阶段这个SO线程,看看是否像OrderedHash任何东西,而不需要我一个巨大的图书馆下降已经存在。 我很失望。 所以,我写我自己。 现在我分享。
Answer 11:
这是解决方案,只需要标准模板库,而无需使用升压转换器的多指标:
你可以使用std::map<std::string,int>;
和vector <data>;
其中在图你存储在矢量和矢量存储数据的数据中插入的顺序位置的索引。 这里对数据的访问具有O(log n)的复杂性。 在插入顺序显示数据具有O(N)的复杂性。 数据的插入有O(log n)的复杂性。
例如:
#include<iostream>
#include<map>
#include<vector>
struct data{
int value;
std::string s;
}
typedef std::map<std::string,int> MapIndex;//this map stores the index of data stored
//in VectorData mapped to a string
typedef std::vector<data> VectorData;//stores the data in insertion order
void display_data_according_insertion_order(VectorData vectorData){
for(std::vector<data>::iterator it=vectorData.begin();it!=vectorData.end();it++){
std::cout<<it->value<<it->s<<std::endl;
}
}
int lookup_string(std::string s,MapIndex mapIndex){
std::MapIndex::iterator pt=mapIndex.find(s)
if (pt!=mapIndex.end())return it->second;
else return -1;//it signifies that key does not exist in map
}
int insert_value(data d,mapIndex,vectorData){
if(mapIndex.find(d.s)==mapIndex.end()){
mapIndex.insert(std::make_pair(d.s,vectorData.size()));//as the data is to be
//inserted at back
//therefore index is
//size of vector before
//insertion
vectorData.push_back(d);
return 1;
}
else return 0;//it signifies that insertion of data is failed due to the presence
//string in the map and map stores unique keys
}
Answer 12:
你需要考虑的一件事是你正在使用的数据元素的小数目。 这是可能的,这将是更快地只使用矢量。 存在这样会使它是做小数据集不是简单的向量查找更加昂贵的地图一些开销。 所以,如果你知道你将永远是围绕使用相同数量的元素,做一些基准测试,看看地图,矢量的表现是什么,你真的认为这是。 您可能会发现,只有50个元素的矢量查找附近一样的地图。
Answer 13:
使用boost::multi_index
地图和列表索引。
Answer 14:
对(STR,int)和静态INT上插入递增的映射调用数据的索引对。 在结构中可以与也许是指数()成员返回静态INT VAL放?
文章来源: A std::map that keep track of the order of insertion?