Какова правильная структура данных для очереди, которая поддерживает операции Min, Max в O (1) раз?

Какова правильная структура данных для очереди, поддерживающей операции Enque, Dequeue, Peak, Min и Max и выполняющая все эти операции в течение O (1).

Наиболее очевидной структурой данных является связанный список, но Min, Max операций будет O (n). Priority Queue - еще один отличный выбор, но Enqueue, Dequeue должен работать обычным образом в очереди. (FIFO)

И еще один вариант, который приходит на ум - это куча, но я не могу понять, как можно создать очередь с помощью операции Min, Max с помощью Heaps.

Любая помощь очень ценится.

Ответы

Ответ 1

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

Поскольку вам требуются enqueue() и dequeue(), элементы должны быть добавлены и удалены по порядку прибытия (FIFO). Простая двойная очередь (связанная или использующая круговой вектор) обеспечила бы это в O (1).

Но добавляемые элементы могут изменять текущие значения min() и max(); однако при удалении старые значения min() и max() должны быть восстановлены... если только они не были удалены промежутком времени. Это ограничение заставляет вас как-то убирать элементы. Любая структура сортировки (min-heap, max-heap, сбалансированное двоичное дерево,...) потребует, по крайней мере, O (log n), чтобы найти позицию нового прибытия.

Лучше всего парировать сбалансированное двоичное дерево (для min() и max()) с двусвязным списком. Ваши узлы дерева будут хранить набор указателей на узлы списка, отсортированные по любой клавише, которую вы используете в min() и max(). В Java:

// N your node class; can return K, comparable, used for min() and max() 
LinkedList<N> list;           // sorted by arrival
TreeMap<K,HashMap<N>> tree;   // sorted by K
  • в enque(), вы добавите новый node в конец list и добавите тот же самый node по его ключу в HashMap в своем node в tree. O (log n).
  • в dequeue() вы удалите node с начала list и из своего HashMap в дереве node. O (log n).
  • в мин(), вы должны искать 1-й элемент в дереве. O (1). Если вам нужно удалить его, у вас есть указатель на связанный список, поэтому O (1) с этой стороны; но O (log n), чтобы перебалансировать дерево, если это был последний элемент с этим конкретным K.
  • в max() применяется одна и та же логика; за исключением того, что вы будете искать последний элемент в дереве. Итак, O (log n).
  • on peek(), просмотр, но не извлечение 1-го элемента в очереди, будет O (1).

Это можно упростить (удалив HashMap), если вы знаете, что все ключи будут уникальными. Однако это не влияет на асимптотические затраты: все они останутся прежними.

На практике разница между O (log n) и O (1) настолько мала, что реализация карты по умолчанию в С++ STL равна O (log n) (дерево вместо Hash).

Ответ 2

Любая структура данных, которая может извлекать Min или Max в O (1), должна тратить не менее O (log n) на каждые Insert и Remove для поддержки элементов в частично отсортированном порядке. Структуры данных, которые достигают этого, называются очередями приоритетов.

Основная очередь приоритетов поддерживает Insert, Max и RemoveMax. Есть несколько способов их создания, но бинарные кучи работают лучше всего.

Поддержка всех Insert, Min, RemoveMin, Max и RemoveMax с одной очередью приоритетов более сложна. Способ работы с единой структурой данных, адаптированной из двоичной кучи, описан в статье:

Аткинсон, Майкл Д. и др. "Кучи Min-max и генерализованные очереди приоритетов." Связь ACM 29.10 (1986): 996-1000.

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

Ответ 3

Эта структура НЕ существует!

Существует простой способ утвердить этот вывод.

Как мы все знаем, сложность задачи сортировки O (nlogn). Но если структура, о которой вы сказали, существует, будет решение для сортировки:

  • Завершить каждый элемент один за другим стоит O (n)
  • Декомментировать каждый элемент max (или min) один за другим стоит O (n)

что означает, что проблема сортировки может быть решена O (n). Но это НЕВОЗМОЖНО.

Ответ 4

Предположения:

что вы заботитесь только о производительности, а не о пространстве/памяти/...

Решение:

Это индекс - это набор, а не список (будет работать для списка, но может потребоваться дополнительная любовь)

Вы можете сделать очередь и хэш-таблицу бок о бок.

Пример:

Допустим, что порядок 5 4 7 1 8 3

Очередь → 547813

Таблица хэшей → 134578

Enqueue:

1) Возьмите свой объект и вставьте в хеш-таблицу в правом ковше. Min/Max всегда будет первым и последним индексом. (см. отсортированные хеш-таблицы)

2) Затем вставьте в свою очередь, как обычно.

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

Обе операции с большой хэш-таблицей будут O (1)

Dequeue:

1) Поместите первый элемент O (1)

2) удалить элемент из хеш-таблицы O (1)

Мин/Макс:

1) Посмотрите на свою хэш-таблицу. В зависимости от используемого языка теоретически можно найти его, взглянув на голову стола или на хвост таблицы.

Для лучшего объяснения отсортированных хеш-таблиц fooobar.com/info/383481/...

Примечание: Я хотел бы отметить, что нет "нормальной" структуры данных, которая будет делать то, что вы требуете от меня. Однако это не означает, что это невозможно. Если вы попытаетесь реализовать структуру данных, скорее всего, вам придется сделать это для своих нужд и не сможете использовать имеющиеся текущие библиотеки. Вам может потребоваться использовать язык с очень низким уровнем, например, сборку, чтобы достичь этого, но, возможно, C или Java могут иметь возможность, если вы хорошо относитесь к этим языкам.

Удачи.

EDITED: Я не объяснял отсортированные хеш-таблицы, поэтому добавила ссылку на другую SO, чтобы объяснить их.