C++ 跟踪插入顺序的std::map?
我目前有一个C++ 跟踪插入顺序的std::map?,c++,dictionary,std,insertion-order,C++,Dictionary,Std,Insertion Order,我目前有一个std::map,它将一个整数值存储到一个唯一的字符串标识符中,我确实使用该字符串进行查找。它主要做我想要的,除了它不跟踪插入顺序。因此,当我迭代映射以打印出值时,它们会根据字符串进行排序;但是我希望它们按照(第一次)插入的顺序进行排序 我考虑改用向量,但我需要查找字符串并将整数值增加10000000倍,因此我不知道std::vector是否会明显变慢 是否有一种方法可以使用std::map或者是否有另一种std容器更适合我的需要 [我使用的是GCC 3.4,我的std::map]中
std::map
,它将一个整数值存储到一个唯一的字符串标识符中,我确实使用该字符串进行查找。它主要做我想要的,除了它不跟踪插入顺序。因此,当我迭代映射以打印出值时,它们会根据字符串进行排序;但是我希望它们按照(第一次)插入的顺序进行排序
我考虑改用向量
,但我需要查找字符串并将整数值增加10000000倍,因此我不知道std::vector
是否会明显变慢
是否有一种方法可以使用std::map
或者是否有另一种std
容器更适合我的需要
[我使用的是GCC 3.4,我的std::map
]中的值可能不超过50对
谢谢。你不能用地图来做这件事,但是你可以使用两个独立的结构-地图和向量,并保持它们的同步-也就是说,当你从地图中删除时,从向量中查找并删除元素。或者,您可以创建一个
映射
——并在插入时将映射的大小()与int值一起存储到记录位置中,然后在打印时,使用position成员进行排序。如果您需要两种查找策略,则最终将得到两个容器。您可以使用带有实际值(int
s)的向量,并在其旁边放置map::difference\u type>
,将索引返回到向量中
为了完成这一切,您可以将两者封装在一个类中
但我相信有多个索引。如果std::map中只有50个值,那么可以在打印出来之前将它们复制到std::vector,然后使用适当的函子通过std::sort进行排序
或者你可以用。它允许使用多个索引。
在您的情况下,它可能如下所示:
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;
结构值{
字符串s;
int i;
};
结构字符串_标记{};
typedef多索引容器<
价值,,
索引<
随机访问,//此索引表示插入顺序
哈希_unique<标记,成员>
>
>价值观;
您可以将std::vector
与std::tr1::无序映射(哈希表)组合在一起。这里有一个指向无序地图的链接。可以使用向量跟踪插入顺序,使用哈希表进行频繁查找。如果要进行成千上万次的查找,那么std::map
的O(logn)查找和哈希表的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';
}
std::向量插入顺序;
std::tr1::无序映射myTable;
//初始化哈希表并记录插入顺序。
myTable[“foo”]=0;
插入顺序。向后推(“foo”);
myTable[“bar”]=0;
插入顺序。向后推(“杆”);
myTable[“baz”]=0;
插入顺序。向后推(“baz”);
/*将myTable中的内容增加100000倍*/
//打印最终结果。
对于(int i=0;i std::cout这在某种程度上与Faisals answer有关。您只需围绕映射和向量创建一个包装类,并轻松保持它们的同步。适当的封装将允许您控制访问方法,从而控制使用哪个容器…向量或映射。这避免了使用Boost或其他类似的方法。另一种实现方法nt这是一个映射
而不是向量
。我将向您展示此方法并讨论其区别:
只需创建一个在幕后有两个贴图的类
#include <map>
#include <string>
using namespace std;
class SpecialMap {
// usual stuff...
private:
int counter_;
map<int, string> insertion_order_;
map<string, int> data_;
};
有很多方法可以让设计变得更好并担心性能,但这是一个很好的框架,可以让您开始自己实现此功能。您可以将其模板化,并且您可以实际将对作为值存储在数据中,以便您可以轻松地按插入顺序引用条目。但是我将这些设计留给您gn问题作为练习:-)
更新:我想我应该谈谈使用map和vector进行插入顺序的效率_
- 直接查找数据,在这两种情况下都是O(1)
- 向量法中的插入为O(1),映射法中的插入为O(logn)
- 向量方法中的删除是O(n),因为您必须扫描要删除的项。映射方法中的删除是O(logn)
也许如果你不打算多使用删除,你应该使用向量方法。如果你支持不同的顺序(比如优先级),映射方法会更好你需要考虑的是你所使用的数据元素的数量很少。它可能会更快地使用向量。在地图中有一些开销会导致它比简单的向量在查找小数据集时花费更高。因此,如果你知道你将永远B。e使用大约相同数量的元素,进行一些基准测试,看看映射和向量的性能是否与您真正认为的一样。您可能会发现,在只有50个元素的向量中查找与映射几乎相同。保持平行的列表插入顺序
打印时,在列表上迭代并查找地图
//应该像这个男人
//这保持了插入的复杂性是O(logN),删除也是O(logN)
类特殊映射{
私人:
int计数器;
地图插入顺序;
映射插入\u顺序\u反转\u查找;//这里的解决方案只需要标准模板库,而不需要使用boost的多索引:
您可以使用std::map;
和vector;
在map中,您将数据位置的索引存储在vector中,vector按插入顺序存储数据。在这里,对数据的访问具有O(logn)复杂性。以插入方式显示数据
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;
}
each element in insertionOrder // walks in insertionOrder..
print map[ element ].second // but lookup is in map
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_;
};
#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
}
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();
}
#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;
}
}