Прежде всего, учитывая, что у вас есть сценарий ключ / значение, вам, вероятно, следует использовать ассоциативный контейнер.
Если вы используете старый старый C ++ и не имеете Boost, следуйте совету Стива Джессопса и просто используйте std::map
, если у вас есть C ++ 0x или Boost, вам лучше использовать hash_map
или unordered_map
: он просто лучше соответствует вашим требованиям (в конце концов, вам не нужно заказывать игроков по идентификатору, вы просто хотите быстро их найти) и, вероятно, будет быстрее, учитывая количество игроков.
Для управления top20 у вас есть 2 варианта:
- Вы можете использовать библиотеку Boost.MultiIndex для создания одного уникального контейнера, который одновременно предлагает быстрый поиск по идентификатору (используя хэш-карту) и упорядоченный индекс по счету ... однако заказывать всех игроков - пустая трата когда вам нужно только 20 из них
- Вы можете просто управлять отдельной структурой, такой как
vector
указателей для пользователей, и каждый раз, когда вы изменяете счет проверки пользователя, она должна заменять пользователя в векторе
Последнее решение, хотя и простое, предполагает, что игрок не может потерять очки ... гораздо сложнее, если это может произойти.
class UsersCollection;
class User
{
public:
void incrementScore(size_t term);
private:
size_t mId;
size_t mScore;
UsersCollection& mCollection;
};
class UsersCollection
{
public:
static const size_t MNumberHiScores = 20;
static const size_t MNotAChampion = -1;
UsersCollection(DBConnection const&);
// returns either the position of the user in
// the hi scores vector or MNotAChampion
size_t insertUserInHiScores(User const& user);
private:
std::unordered_map<size_t, User> mUsers;
std::vector<User const*> mHiScores; // [1]
};
void User::incrementScore(size_t term)
{
mScore += term;
mCollection.insertUserInHiScores(*this);
}
struct UserSort: std::binary_function<User const*, User const*, bool>
{
bool operator()(User const* lhs, User const* rhs) const
{
return lhs->score() > rhs->score();
}
};
size_t UsersCollection::insertUserInHiScores(User const& user)
{
std::vector<User const*>::const_iterator it =
std::find(mHiScores.begin(), mHiScores.end(), &user);
if (it == mHiScores.end()) // not among the hiscores
{
mHiScores.push_back(&user);
}
std::sort(mHiScores.begin(), mHiScores.end(), UserSort());
if (mHiScores.size() > MNumberHiScores) // purge if too many users
{
User const* last = mHiScores.back();
mHiScores.pop_back();
if (&user == last) return MNotAChampion;
}
// return position in the vector in the [0, MNumberHiScores) range
return std::find(mHiScores.begin(), mHiScores.end(), &user)
- mHiScores.begin();
}
Примечание (1): использование set
может показаться хорошей идеей, однако набор предполагает, что элементы не меняются, и это не так. Это могло бы сработать, если бы мы были очень осторожны:
- удалить пользователя из
set
до изменения счета
- возвращение пользователя после его изменения
- при желании выталкивать последние элементы, если их слишком много