Эффективная структура данных для списка лидеров, т.е. список записей (имя, баллы) - Эффективный поиск (имя), Поиск (ранг) и Обновление (баллы)

Пожалуйста, предложите структуру данных для представления списка записей в memory. Каждая запись состоит из:

  • Имя пользователя
  • Точки
  • Ранг (на основе очков) - необязательное поле - может быть либо сохранено в записи, либо может быть вычислено динамически

Структура данных должна поддерживать эффективную реализацию следующих операций:

  • Вставить (запись) - может изменить ряды существующих записей
  • Удалить (запись) - может изменить ранжирование существующих записей
  • GetRecord (name) - Возможно, будет создана хэш-таблица.
  • GetRecord (ранг)
  • Обновление (точки) - может изменить ряды существующих записей

Моя основная проблема - эффективная реализация GetRecord (rank), поскольку ранги могут часто меняться.

Я предполагаю, что встроенная память DBMS будет хорошим решением, но, пожалуйста, не предлагайте ее; пожалуйста, предложите структуру данных.

Ответ 1

По сути, вам просто понадобится пара сбалансированных деревьев поиска, которые позволят O (lg n) вставлять, удалять и операции getRecord. Хитрость заключается в том, что вместо хранения фактических данных в деревьях вы будете хранить указатели на набор объектов записей, где каждый объект записи будет содержать 5 полей:

  1. имя пользователя
  2. стоимость балла
  3. Оценка
  4. указатель назад на узел в дереве имен, который ссылается на объект
  5. указатель назад на узел в дереве точек, который ссылается на объект.

Дерево имен изменяется только при добавлении новых записей и при удалении записей. Дерево точек модифицируется для вставок и удалений, а также для обновлений, где соответствующая запись найдена, удален указатель на дерево точек, обновлен счетчик точек, а затем добавлен новый указатель на дерево точек.

Как вы упомянули, вы можете использовать хеш-таблицу вместо дерева имен, если хотите. Ключевым моментом здесь является то, что вы просто поддерживаете отдельные отсортированные индексы в виде набора неупорядоченных записей, которые сами содержат указатели на их узлы индекса.


Дерево точек будет представлять собой некоторую вариацию в дереве статистики заказов, которое вместо того, чтобы быть конкретной структурой данных, является общим термином для двоичного дерева поиска, операции которого модифицированы для поддержания инварианта, который делает запрошенный ранг связанные операции более эффективны, чем ходьба по дереву. Детали того, как поддерживаются инварианты, зависят от используемого сбалансированного дерева поиска (красно-черное дерево, дерево avl и т.д.).

Ответ 2

Должна работать скиписта + hashmap.

Вот реализация в Go: https://github.com/wangjia184/sortedset

Каждый node в наборе связан с этими свойствами.

  • key - это уникальный идентификатор node, который является "именем пользователя" в вашем случае.
  • value - любое значение, связанное с node
  • score число решает порядок (ранг) в наборе, который является "точками" в вашем случае

Каждый node в наборе связан с ключом. Хотя ключи уникальны, баллы могут повторяться. Узлы принимаются по порядку (от низкого балла до высокий балл) вместо заказа после. Если оценки совпадают, node упорядочивается по его ключу в лексикографическом порядке. Каждый node в также можно получить доступ по рангу, который представляет собой позицию в отсортированный набор.

Типичный пример использования сортированного набора - это доска лидеров в массовом онлайн-режиме игра, где каждый раз, когда появляется новый счет, вы обновляете его, используя AddOrUpdate(). Вы можете легко использовать лучших пользователей, используя GetByRankRange(), вы также можете, учитывая имя пользователя, вернуть его рангом в списке с использованием метода FindRank(). Использование FindRank() и GetByRankRange() вместе вы можете показать пользователям со счетом, подобным данного пользователя. Все очень быстро.

Ответ 3

Найдите СУБД, которая включает функцию для выбора записи по порядковому номеру записи.

Смотрите: Как выбрать n-я строка в таблице базы данных SQL?

Построить таблицу с столбцом UserName и столбцом Points. Сделать UserName основным индексом. Постройте вторичный неисторический поддерживаемый индекс в точках.

Чтобы получить запись с рангом R, выберите индекс по точкам и перейдите к записи R.

Это заставляет СУБД выполнять большую часть работы и упрощает вашу часть.