Дек
Версия от 02:44, 6 января 2016; Mutsch (обсуждение | вклад)
Определение
Дек (от англ. deque — double ended queue) — структура данных, представляющая из себя список элементов, в которой добавление новых элементов и удаление существующих производится с обоих концов. Дек можно воспринимать как двустороннюю очередь или двусторонний стек. Он имеет следующие операции:
- — проверка на наличие элементов,
- (запись в конец) — операция вставки нового элемента в конец,
- (снятие с конца) — операция удаления конечного элемента,
- (запись в начало) — операция вставки нового элемента в начало,
- (снятие с начала) — операция удаления начального элемента.
Реализации
Дек расходует только
памяти, на хранение самих элементов.На массиве
Ключевые поля:
- — массив, с помощью которого реализуется дек, способный вместить не более элементов,
- — индекс головы дека,
- — индекс хвоста дека.
Дек состоит из элементов
. Всего дек способен вместить не более элементов, поэтому при переполнении приходится перевыделять память и копировать все элементы.boolean empty(): return d.head % n + 1 == d.tail
function pushBack(x : T): if (d.head == d.tail) return error "overflow" d[d.tail] = x d.tail = (d.tail - 2 + n) % n + 1
T popBack(): if (empty()) return error "underflow" d.tail = d.tail % n + 1 return d[d.tail]
function pushFront(x : T): if (d.head == d.tail) return error "overflow" d[d.head] = x d.head = d.head % n + 1
T popFront(): if (empty()) return error "underflow" d.head = (d.head - 2 + n) % n + 1 return d[d.head]
Все операции выполняются за
.На саморасширяющемся массиве
Ключевые поля:
- — массив, в котором хранится дек,
- — временный массив, где хранятся элементы после перекопирования,
- — индекс головы дека,
- — индекс хвоста дека,
- — размер массива.
Если реализовывать дек на динамическом массиве, то мы можем избежать ошибки переполнения. При выполнении операций
происходит проверка на переполнение и, если нужно, выделяется большее количество памяти под массив. Также проверяем, не нужно ли нам уменьшить размер массива при выполнении операций и . Для удобства выделим в отдельную функцию получение размера дека.int size() if d.tail > d.head return n - d.tail + d.head - 1 else return d.head - d.tail - 1
function pushBack(x : T): if (d.head == d.tail) T newDeque[capacity * 2] for i = 1 to capacity - 1 newDeque[i] = d[d.tail + 1] d.tail = d.tail % n + 1 d = newDeque d.tail = capacity * 2 d.head = capacity - 1 capacity = capacity * 2 d[d.tail] = x d.tail = (d.tail - 2 + n) % n + 1
T popBack(): if (empty()) return error "underflow" if (size() < capacity / 4) T newDeque[capacity / 2] for i = 1 to size() newDeque[i] = d[d.tail + 1] d.tail = d.tail % n + 1 d = newDeque d.tail = capacity / 2 d.head = size() + 1 d.tail = d.tail % n + 1 return d[d.tail]
function pushFront(x : T): if (d.head == d.tail) T newDeque[capacity * 2] for i = 1 to capacity - 1 newDeque[i] = d[d.tail + 1] d.tail = d.tail % n + 1 d = newDeque d.tail = capacity * 2 d.head = capacity - 1 d[d.head] = x d.head = d.head % n + 1
T popFront(): if (empty()) return error "underflow" if (size() < capacity / 4) T newDeque[capacity / 2] for i = 1 to size() newDeque[i] = d[d.tail + 1] d.tail = d.tail % n + 1 d = newDeque d.tail = capacity / 2 d.head = size() + 1 d.head = (d.head - 2 + n) % n + 1 return d[d.head]
На списке
Ключевые поля:
-
ListItem(data : T, next : ListItem, prev : ListItem)
— конструктор, - — ссылка на хвост,
- — ссылка на голову.
Дек очень просто реализуется на двусвязном списке. Элементы всегда добавляются либо в
, либо в . В данной реализации не учитывается пустой дек.function pushBack(x : T): tail = ListItem(x, tail, null) tail.next.prev = tail
T popBack(): data = tail.data tail = tail.next return data
function pushFront(x : T): head = ListItem(x, null, front) head.prev.next = head
T popFront(): data = head.data head = head.prev return data
На двух стеках
Ключевые поля:
- — ссылка на хвост,
- — ссылка на голову.
Храним два стека -
и . Левый стек используем для операций и и .function pushBack(x : T): leftStack.push(x)
T popBack(): if not leftStack.empty() return leftStack.pop() else while not rightStack.empty() leftStack.push(rightStack.pop()) return leftStack.pop()
function pushFront(x : T): rightStack.push(x)
T popFront(): if not rightStack.empty() return rightStack.pop() else while not leftStack.empty() rightStack.push(leftStack.pop()) return rightStack.pop()