この場合の実際のO(1)操作は非常に複雑な問題であり、STL の使用を好むことを考慮すると、次のデータ構造のようなものをお勧めします。これが Big-Oh の要件を満たさないというわけではなく、STL を使用しても実装できる最も効率的な方法ではありませんが、シンプルで効率的です。
主なデータ構造はstd::map
. std::unordered_map
しかし、O(1) へのルックアップを高速化するには、次のように使用できます。
using std::map, std::string, std::vector, std::unordered_map;
typedef map<string, vector<int> > TestTakersMap;
typedef unordered_map<string, TestTakersMap::iterator> LookupAccelerator;
これで、さまざまな操作が次のようになります。
- 新しい人物の追加: マップに挿入しますが、新しいレコードを unordered_map に挿入したマップに名前とイテレータも追加します。O(ログ(N)) .
- 人を調べる: unordered_map を使用して、その人のイテレータとデータを取得できます。O (1)が必要です。
- Add a new score : unordered_map を使用して人を見つけ、取得したイテレータを使用して新しいスコアを追加します。償却 O(1)。
- すべての名前とスコアの出力: マップ自体を反復処理し、並べ替え手順を追加せずに名前を辞書順に取得します。O(S)と見なすことができます。ここで、Sはすべての参加者のスコアの合計数です。
このすべてにおいて、ボトルネックはキャッシュになることに注意してください。このすべてのポインターがメモリ内で追跡およびジャンプしても、まったく役に立ちません。もちろん、これは他のいくつかの要因に依存します。たとえば、実際に獲得した名前の数、1 人あたりのスコア数、新しい人物を追加する頻度、新しいスコアを追加する頻度、すべてのスコアを印刷する頻度などです。名前とスコア、1 人あたりおよびテストあたりのデータの量と必要量など。
UPDATE : 次のような基本的な操作を実行できます。インクルードなどは次のようになります。
#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;
};