2014-03-01 3 views
2

Я должен реализовать структуру данных, которая поддерживает следующие три функции. Данные представляют собой пару (a, b) двух двойных значений и данные сосредоточены в конкретной области. Скажем, со значениями 'a' в диапазоне 500-600.Реализация структуры данных, поддерживающей различные операции

  1. Вставить (double a, double b) - Вставить данные, пару (двойную, двойную) в структуру данных. Если первый элемент пары уже существует, обновите его второй элемент до нового значения.

  2. Удалить (double a) - Удалить данные, содержащие первый элемент = a.

  3. PrintData (int count) - печать значения данных с наибольшим значением count. Значение сравнивается по данным. Первое.

Вводный файл содержит ряд операций Insert, Delete и PrintData. В настоящее время я реализовал структуру данных как сбалансированное по высоте дерево двоичного поиска с использованием STL-Map, но это недостаточно быстро.

Есть ли другая реализация, которая быстрее, чем карта. Мы можем использовать кеширование для хранения наиболее распространенных запросов PrintData.

+0

@Inertiatic. Приоритетная очередь не будет (эффективно) поддерживать запрос «count-th наибольшее значение» в соответствии с № 3. – Dukeling

+0

@ Dukeling Я, должно быть, неправильно понял вопрос. Edit: Вы правы, я вижу, где я сбежал. Удалить должен искать и удалять этот элемент, который может находиться где угодно в структуре данных. – Inertiatic

+0

Как любые элементы в структуре данных? Если не существует много тысяч, вероятно, что использование упорядоченного вектора ключа и параллельного вектора со значениями и вставка/удаление в них происходит намного быстрее! Если вы можете разумно вешать элементы, например, используя преобразование в 'int', а затем поиск в векторе, вы можете эффективно расширить структуру данных до гораздо большего количества элементов. При обновлении значения вы также должны немедленно сохранить текущее максимальное значение/счетчик, если счетчик больше текущего (нет необходимости искать его). –

ответ

2

Я рекомендую 2 бинарных деревьев поиска (BSTs) - одна будучи карта от a до b (отсортированный по a), другие должны быть отсортированы по b.

Вторым должен быть пользовательский BST - вам нужно, чтобы каждый узел хранил счетчик количества узлов в поддереве с ним как root - эти подсчеты могут быть обновлены в O (log n), и позволит запросам O (log n) получить k-й наибольший элемент.

При выполнении вставки вы просто сначала посмотрите значение b в первом BST, затем удалите это значение из второго, затем обновите первое и вставьте новое значение во второе.

Для удаления вы просто будете искать значение b в первом BST (и удалить эту пару), а затем удалить это значение из второго.

Все упомянутые операции должны принимать O (log n).

Кэширование

Если вы, к примеру, только собираетесь запросить верхние 10 элементов, можно поддерживать другой BST, содержащий только те 10 элементов (или даже просто необязательно, отсортированный массив, так как есть только 10 элементов), которые мы затем запросим вместо второго BST выше.

При вставке также вставляйте в эту структуру, если значение больше наименьшего, и удалите наименьшее значение.

При удалении нам нужно найти следующее самое большое значение и вставить его в маленький BST. Хотя это также можно сделать лениво - при удалении просто удалите его из этого BST - не заполняйте его до 10 раз. При запросе, если в этом BST есть достаточно элементов, мы можем просто искать его, иначе мы найдем все значения в большом BST, необходимые для заполнения этого BST, а затем мы запрашиваем.

Это приведет к запросу O (1) в наилучшем случае (наихудший вариант O (log n)), в то время как другие операции будут по-прежнему равны O (log n).

Хотя добавленная сложность, вероятно, не стоит того - O (log n) довольно быстро, даже для большого n.

Основываясь на этой идее, мы могли бы только есть этот маленький BST вместе с отображением BST a в b - это потребовало бы, что мы проверяем все значения, чтобы найти нужные из них во время выполнения запроса после удаления, так что это будет только действительно выгодно, если нет большого количества изъятий.

+0

Как мы можем использовать кеширование для третьей операции, учитывая, что функция PrintData принимает параметр только в диапазоне 1-10. – Hellboy

+0

@ Хеллбой См. Править. – Dukeling

+0

Если мы не рассматриваем кеширование, почему второй (пользовательский) BST сортируется по значению «b», так как упорядочение данных выполняется с помощью значения «a». Кроме того, вставка выполняется в соответствии со значением «a». Даже после кэширования я не думаю, что это достаточно быстро. Мне нужно уменьшить количество циклов процессора, принятых для всех операций. – Hellboy

2

Я бы порекомендовал indexed skip list. Это даст вам O (log n) вставить и удалить, а O (log n) получит доступ к n наибольшему значению (при условии, что вы поддерживаете список в порядке убывания).

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

original skip list paper.

+0

Но сложность вложения/удаления/поиска в худшем случае в списке пропуска равна O (n) – Hellboy

+0

@Hellboy: Да, худшим случаем является O (n). В документе говорится, что наихудший случай почти невозможно встретить. Мой опыт подтверждает это. Я часто использовал списки пропусков и * никогда не сталкивался ни с чем, даже приближаясь к этому патологическому поведению. Я не говорю, что этого не может быть, просто маловероятно. –

Смежные вопросы