Учитывая, что реальный O (1) операция в этом случае является очень сложной проблемой, и вы предпочитаете использовать STL, я бы предложил что-то вроде следующих структур данных. Не то чтобы это не удовлетворяло вашим требованиям Big-Oh, и это не самый эффективный способ реализовать его даже с STL, но он прост и эффективен.
Ваша основная структура данных - std::map
. Но для того, чтобы ускорить Lookups в 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;
Теперь ваши различные операции будут:
- Добавить новый человек: Вы вставляете в карту, но также вы добавляете имя и итератор на карте, где вы вставили новую запись в unordered_map. O (log (N)).
- Поиск человека: Используя unordered_map, вы можете получить итератор и данные для этого человека.ОжидаемыеO (1).
- Добавить новую оценку: Вы найдете человека, использующего unordered_map, а затем используйте итератор, который вы получили, чтобы добавить новый балл. АмортизированныйO (1).
- Распечатка всех имен и оценок: Вы итератор над самой картой и получите имена в лексикографическом порядке без добавления шага сортировки. Можно считать O (S), где S - общее количество баллов для всех участников.
Обратите внимание, что во всем этом, узким местом будет ваш кэш, и все это указатель чеканка и прыгали в памяти будет не поможет вам на всех. Конечно, это зависит от нескольких других факторов, например, от количества имен, которые вы на самом деле получили, количества очков на человека, как часто вы добавляете нового человека, как часто вы добавляете новый балл, как часто вы печатаете все имена и баллы, сколько у вас данных и потребностей на человека и за один тест и т. д.
ОБНОВЛЕНИЕ: Вы можете выполнять основные операции, такие как следующее. Включения и т. Д. Выглядят так:
#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;
};
Если вы часто вставляете ключи, используйте связанный список, который вставляет в O (1). Если вы часто извлекаете их, используйте массив, который имеет время поиска O (1). – 2013-03-30 06:12:33
ЕСЛИ «каждый час» часто для вас, просто идите и выбирайте все, что захотите. Это не изменит ситуацию. – Blindy
@ H2CO3 С помощью (отсортированного) связанного списка требуется 'O (n)', чтобы найти правильную позицию вставки. – timrau