Структура данных для очереди транзакций - PullRequest
0 голосов
/ 15 марта 2011

Существует ли более подходящая / эффективная структура данных для очереди транзакций, чем использование списка.Я пытался использовать Очереди и Стеки, но ни один из них не соответствует требованиям.

Ниже я подробно изложил свою проблему с примерами, показывающими, почему я на данный момент получил Список.Любые предложения альтернативных структур данных (предпочтительно, но не ограничиваясь теми, которые имеют реализацию в .Net BCL) приветствуются.

Проблема

Поддерживать очередь транзакций Insert() / Delete()операции, которые впоследствии будут сохранены в произвольном резервном хранилище, когда пользователь вызывает метод Commit(), или отменяются, когда они вызывают метод Rollback().

Операции должны выполняться в состоянии в памяти затрагиваемого объектапоскольку последующие операции могут зависеть от состояния объекта, созданного предыдущими операциями.

Пример 1

У меня есть объект obj, который начинается как пустая коллекция.Пользователь вставляет элемент i, а затем удаляет элемент i.

Затем он вызывает Rollback(), учитывая следующие структуры данных для очереди: при откате происходит следующее:

  • Очередь - obj.Delete(i), obj.Insert(i) -> неверно, поскольку obj должен оставаться пустым после отката
  • Стек - obj.Insert(i), obj.Delete(i) -> правильно, поскольку obj остается пустым
  • Список (Обратный обход) - obj.Insert(i), obj.Delete(i) -> правильно, поскольку obj остается пустым

Если вместо этого они вызывают Commit(), то происходит следующее:

  • Очередь - obj.Insert(i), obj.Delete(i) -> правильно, поскольку obj остается пустым
  • Стек - obj.Delete(i), obj.Insert(i) -> неверно, поскольку obj не являетсяпусто
  • Список (Прямой обход) - obj.Insert(i), obj.Delete(i) -> правильно, поскольку obj остается пустым

Так что в этом примере очередь работает для Commit(), но неRollback() и стек показывает обратное поведение , но оба неверны.Только List показывает правильное поведение, хотя обратите внимание, что для коммита мы пересекаем список в прямом направлении, в то время как для отката мы пересекаем список в обратном направлении.

Пример 2

Теперь рассмотрим сноваобъект obj, который на этот раз начинается с отдельного элемента i, содержащегося в нем.

На этот раз последовательность операций представляет собой удаление i с последующей вставкой i.

Если они вызывают Rollback(), происходит следующее:

  • Очередь - obj.Insert(i), obj.Delete(i) -> неверна, поскольку obj заканчивается как пустой
  • Stack -obj.Delete(i), obj.Insert(i) -> правильно, поскольку obj содержит один элемент i все еще
  • Список (обратный путь) - obj.Delete(i), obj.Insert(i) -> правильно, поскольку obj содержитодин элемент i все еще

Если они вместо этого вызвали Commit(), происходит следующее:

  • Очередь - obj.Delete(i), obj.Insert(i) -> правильно с obj содержит один элемент i все еще
  • стек - obj.Insert(i), obj.Delete(i) -> incorrect, так как obj заканчивается как пустой
  • List (Forward Traversal) - obj.Delete(i), obj.Insert(i) -> правильно, поскольку obj содержит единственный элемент i still

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

Итог

При использованииСписок сам по себе не является неэффективным. Мне просто интересно, существует ли более подходящая структура данных, которая лучше подходит для моей проблемы?

1 Ответ

1 голос
/ 15 марта 2011

Технически вы можете использовать LinkedList<T>.Это как Queue + Stack: вы можете добавлять и удалять из головы и из хвоста, и в обоих случаях это O (1) (но обычно он медленнее, чем List, по причинам, связанным с локальностью памяти и необходимостьювыделять память для каждого добавления элемента)

(Пожалуйста, не убивайте меня, потому что я сказал, что LinkedList<T> похоже на Queue + Stack ... Я знаю разницу ... Яимелось в виду только то, что он может использоваться обоими способами одновременно)

Я добавлю, что если вы считаете Rollback «исключением» (что-то редкое), то вы можете использовать Queueи, когда у вас есть Rollback, Reverse выход Queue с использованием LINQ.Будучи «исключением», он может быть медленнее (и вам даже не нужен LINQ ... Вы можете сделать ToArray() и пройти массив в обратном порядке)

...