Эффективная структура данных для быстрого произвольного доступа, поиска, вставки и удаления

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

Мне нужно четыре основных операции, чтобы быть эффективными, в грубом порядке важности:

  • принимая значение из заданного индекса
  • нахождение индекса заданного значения
  • вставка значения по заданному индексу
  • удаление значения по заданному индексу

Используя массив, у меня есть 1 в O (1), но 2 - O (N), а вставка и удаление дороги (O (N), как я полагаю).

Связанный список имеет O (1) вставку и удаление (после того, как у вас есть node), но 1 и 2 - O (N), таким образом отрицая выигрыш.

Я попытался сохранить два массива [index] = value и b [value] = index, которые превращают 1 и 2 в O (1), но поворачивают 3 и 4 в еще более дорогостоящие операции.

Есть ли структура данных, более подходящая для этого?

Ответ 1

Я бы использовал красно-черное дерево для сопоставления ключей со значениями. Это дает вам O (log (n)) для 1, 3, 4. Он также поддерживает ключи в отсортированном порядке.

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

Ответ 2

Как насчет использования отсортированного массива с бинарным поиском?

Вставка и удаление происходит медленно. но учитывая тот факт, что данные являются целыми числами, можно оптимизировать с помощью вызовов memcpy(), если вы используете C или С++. Если вы знаете максимальный размер массива, вы даже можете избежать распределения памяти во время использования массива, так как вы можете выделить его максимальным размером.

"Лучший" подход зависит от того, сколько предметов вам нужно хранить и как часто вам нужно будет вставлять/удалять по сравнению с поиском. Если вы редко вставляете или удаляете отсортированный массив с O (1) доступом к значениям, безусловно, лучше, но если вы часто вставляете и удаляете, двоичное дерево может быть лучше, чем массив. Для достаточно малого n массив, скорее всего, будет бить дерево в любом случае.

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

Возможно, вам захочется рассказать о том, что быстрее, копировать целые числа, если вы вставляете/удаляете из отсортированного массива или дерево с его выделениями памяти (de).

Ответ 3

Используйте вектор для доступа к массиву.

Используйте карту в качестве индекса поиска для индекса в вектор.

  • , учитывая индекс, выберите значение из вектора O (1)
  • задайте ключ, используйте карту, чтобы найти индекс значения. O (LNN)
  • вставить значение, отбросить назад вектор O (1), вставить индекс в отображение O (lnN)
  • удалить значение, удалить с карты O (lnN)

Ответ 4

Я не знаю, какой язык вы используете, но если это Java, вы можете использовать LinkedHashMap или подобную коллекцию. Он получил все преимущества списка и карты, обеспечивает постоянное время для большинства операций и имеет площадь памяти слона.:)

Если вы не используете Java, идея LinkedHashMap, вероятно, по-прежнему подходит для удобной структуры данных для вашей проблемы.

Ответ 5

Как оформить карту? log (n) для описанных операций.

Ответ 6

Мне нравятся сбалансированные бинарные деревья. Они иногда медленнее, чем хеш-таблицы или другие структуры, но они гораздо более предсказуемы; они обычно O(log n) для всех операций. Я бы предложил использовать Red-black tree или дерево AVL.

Ответ 7

Как достичь 2 с RB-деревьями? Мы можем заставить их подсчитывать своих детей при каждой операции вставки/удаления. Это не приводит к тому, что эти операции значительно продлеваются. Затем спускаться по дереву, чтобы найти i-й элемент, можно в log n time. Но я не вижу реализации этого метода в java или stl.

Ответ 8

Если вы работаете в .NET, то в соответствии с документами MS http://msdn.microsoft.com/en-us/library/f7fta44c.aspx

  • SortedDictionary и SortedList имеют O (log n) для извлечения
  • SortedDictionary имеет O (log n) для операций вставки и удаления, тогда как SortedList имеет O (n).

Эти два отличаются использованием памяти и скоростью вставки/удаления. SortedList использует меньше памяти, чем SortedDictionary. Если SortedList заполняется сразу из отсортированных данных, это быстрее, чем SortedDictionary. Таким образом, это зависит от ситуации, которая действительно лучше для вас.

Кроме того, ваш аргумент для связанного списка недействителен, так как может быть O (1) для вставки, но вам нужно пройти список, чтобы найти точку вставки, так что это действительно не так.