我需要的是一个有序的,带有字符串键的关联容器,由数字向量赋值。此外,我需要O(1)
插入时间。
我的描述听起来很抽象,我会给你一个场景:
有在线测试。当一个人参加此测试时,他的名字会被添加到数据库中。如果他们喜欢,人们可以反复参加考试。他们的所有分数都将以他们的名字记录(这是唯一的)。例如,大卫,汤姆,爱丽丝来参加考试几次。该程序应该能够以下列格式打印输出:
Alice 65 70 84
David 98 97 93
Tom 100 45
...
正如您所看到的,他们的名字应按字典顺序打印出来。每当有人参加测试时,他的分数就会被添加到数据库中。由于很多人会参加测试,因此必须O(1)
时间复杂度。但是,打印数据库也经常发生;每秒说一次。因此,不必在每个显示器上明确排序是有利的。
我可以在这里使用哪种数据结构? (STL是首选。)我目前正在使用unordered_map
,因为它给我O(1)
插入,但它不能按字典顺序迭代键。
答案 0 :(得分:4)
可以在O(1)
中插入并在O(n)
中进行有序迭代的容器可用于在线性时间内对字符串进行排序。
我们可以立即得出结论,这个容器不能单独使用比较器,因为基于比较器的排序的下限为O(n log n)
。
只有少数排序算法按线性时间排序,它们通常需要知道您的密钥空间才能工作。这种算法的增量“在线”版本可能对您有用,并且它使用的增量构建的内部数据将成为您的容器。
Here是对线性时间排序算法的讨论。
答案 1 :(得分:1)
考虑到在这种情况下真正的 O(1)操作是一个非常复杂的问题,并且您更喜欢使用STL,我建议使用类似以下数据结构的东西。并不是说这不满足你的Big-Oh要求,即使使用STL也不是最有效的方法,但它简单而有效。
您的主要数据结构是std::map
。但是为了加速对O(1)的查找,你可以像这样使用std::unordered_map
:
using std::map, std::string, std::vector, std::unordered_map;
typedef map<string, vector<int> > TestTakersMap;
typedef unordered_map<string, TestTakersMap::iterator> LookupAccelerator;
现在您的各种操作将是:
请注意,在所有这些中,你的瓶颈将是你的缓存,并且所有这些指针在内存中追逐和跳跃将不帮助你。当然,这取决于其他几个因素,例如,您实际获得了多少名称,每个人有多少分数,添加新人的频率,添加新分数的频率,以及打印所有分数的频率姓名和分数,每人和每次测试所需的数据和需求量等等。
更新:您可以执行以下基本操作。包括等等如下所示:
#include <map>
#include <string>
#include <unordered_map>
#include <vector>
using std::map;
using std::string;
using std::unordered_map;
using std::vector;
这是一个非常简单的类,可以执行您想要的某些操作。请注意,我正在使用C ++ 11功能(auto
,emplace
,...)但不要将此代码视为特别好的编程风格;我不能担保。
class TestScores
{
private:
typedef int ScoreType;
typedef vector<ScoreType> ScoreList;
typedef map<string, ScoreList> TestTakersMap;
typedef unordered_map<string, TestTakersMap::iterator> LookupAccelerator;
public:
bool hasName (string const & new_name) const
{
return m_lookup.end() != m_lookup.find (new_name);
}
// Returns true if the name is really new
bool addName (string const & new_name)
{
if (hasName(new_name))
return false; // name already in there
auto i = m_takers.emplace (new_name, vector<int>()).first;
m_lookup.emplace (new_name, i);
return true;
}
ScoreList const & getScores (string const & name) const
{
// This redirects to the private, non-const version
return const_cast<TestScores *>(this)->getScores(name);
}
void addScore (string const & name, ScoreType new_score)
{
getScores(name).push_back (new_score);
}
private:
// If the name doesn't already exist, it is added!
ScoreList & getScores (string const & name)
{
if (!hasName(name))
addName (name);
return m_lookup[name]->second;
}
private:
TestTakersMap m_takers;
LookupAccelerator m_lookup;
};
答案 2 :(得分:0)
如果您真的认真对待数据集的大小非常大,并且您绝对需要有效的插入,查找和词典迭代,那么您可以查看Judy Arrays。 Judy数组具有快速,内存效率和类似 trie 的关联数据结构。
您可以查看以下两种实现: