Если нам нужны коллекции FIFO или LIFO (в основном push
, pop
и front
/back
), что мы должны использовать в Rust? Что-то вроде std::queue
или std::stack
из С++.
Есть ли коллекции очереди и стека?
Ответ 1
Прежде всего, Rust не предлагает (в стандартной библиотеке) любую библиотеку с гарантированной задержкой для добавления элементов: коллекции Rust обычно могут выделять память при добавлении новых элементов, а выделение памяти может занимать неограниченное количество времени в худшем случай.
При этом для каждого случая есть два претендента:
- стек может быть реализован либо поверх
Vec
, либоLinkedList
(обе функцииpop_back
иpush_back
) - очередь может быть реализована либо поверх
VecDeque
, либоLinkedList
(обе функцииpop_front
иpush_back
)
Разница между Vec*
и LinkedList
заключается в том, что последняя упрощена: для каждого вызова push_back
выполняется выделение памяти. С одной стороны, это здорово, потому что это означает, что стоимость push_back
не зависит от количества элементов, уже находящихся в коллекции, с другой стороны... ну, распределение памяти может занять очень много времени.
Первое немного сложнее:
- он имеет лучшую пропускную способность, благодаря более удобной кешировке
- он имеет дополнительную емкость, гарантируя невыделение
push_back
, пока существует избыточная емкость. - он все еще сохраняет амортизацию O (1)
push_back
, даже если не резервировать избыточную мощность раньше времени
В общем, я бы посоветовал использовать Vec
для стека и VecDeque
для очереди.
Ответ 2
И VecDeque
и LinkedList
имеют push
/pop
_ front
/back
.
Ответ 3
У Матье М. это почти идеально. Vec
- ваш стек (LIFO), а VecDeque
- двусторонняя очередь, которая поддерживает все 4 варианта (FIFO, FILO, LIFO и LILO), используя:
.push_front(x) | .front() | .pop_front()
.push_back(x) | .back() | .pop_back()
Если вы хотите максимально повысить свою эффективность, я рекомендую ознакомиться с разделом "Общие сведения о Rusts Vec и его способности создавать быстрые и эффективные программы". В нем более подробно рассказывается о том, как происходит распределение и перераспределение в Vec
и VecDeque
, но самый большой VecDeque
заключается в том, что если вы можете предсказать максимальное количество элементов, которые вам понадобятся в очереди, вы можете использовать VecDeque::with_capacity(x)
если вы знаете, когда инициализируете его, или .reserve_exact(x)
если в какой-то момент вы точно знаете, сколько еще слотов вам понадобится
Я настоятельно рекомендую ознакомиться с документацией по Rust на std::collections
, в ней есть превосходный список наиболее распространенных коллекций, используемых в Rust, а также предложения о том, когда выбирать каждую из них.
И последнее, VecDeque
не является частью прелюдии по умолчанию в Rust, поэтому, если вы хотите использовать ее, вам нужно включить это:
use std::collections::VecDeque;