Персистентный дек — различия между версиями
| Shersh (обсуждение | вклад) | Shersh (обсуждение | вклад)  | ||
| Строка 1: | Строка 1: | ||
| + | |||
| {{Определение | {{Определение | ||
| |definition =   | |definition =   | ||
| '''Дек''' (англ. deque {{---}} double ended queue {{---}} очередь с двумя концами) {{---}} структура данных с двусторонним доступом к элементам, т. е. их можно удалять и добавлять как в начало, так и в конец дека. | '''Дек''' (англ. deque {{---}} double ended queue {{---}} очередь с двумя концами) {{---}} структура данных с двусторонним доступом к элементам, т. е. их можно удалять и добавлять как в начало, так и в конец дека. | ||
| }} | }} | ||
| − | [[Файл:Deque.png|thumb| | + | [[Файл:Deque.png|thumb|220px|Дек]] | 
| − | |||
| Кроме дека ещё существует структура данных, называемая ''steque'', которая представляет собой объединение стека и очереди - элементы можно добавлять только в один конец, а извлекать можно с обоих. | Кроме дека ещё существует структура данных, называемая ''steque'', которая представляет собой объединение стека и очереди - элементы можно добавлять только в один конец, а извлекать можно с обоих. | ||
| == Эффективная реализация == | == Эффективная реализация == | ||
| − | + | [[Файл:Tree_deque.png|thumb|220px|right|Древовидная структура дека]] | |
| Написать дек на массиве не представляет особого труда, зная уже, как работают стек и очередь. Далее будет приведена реализация операций добавление элемента и извлечение из одного конца дека за истинное время работы <tex> O(\log ~ n). </tex> Добавление и исключение из другого конца делается симметрично. | Написать дек на массиве не представляет особого труда, зная уже, как работают стек и очередь. Далее будет приведена реализация операций добавление элемента и извлечение из одного конца дека за истинное время работы <tex> O(\log ~ n). </tex> Добавление и исключение из другого конца делается симметрично. | ||
| − | |||
| Персистентный дек можно визуально представить как дерево, где каждый узел хранит пару - левый элемент и правый, а также ''ребёнка'' - ссылку на следующий дек. Только с каждым уровнем вложенности левый и правый элемент хранят в два раза больше объектов, чем на предыдущем уровне. | Персистентный дек можно визуально представить как дерево, где каждый узел хранит пару - левый элемент и правый, а также ''ребёнка'' - ссылку на следующий дек. Только с каждым уровнем вложенности левый и правый элемент хранят в два раза больше объектов, чем на предыдущем уровне. | ||
| Строка 71: | Строка 70: | ||
|          /* |          /* | ||
|           * если всё же temp не пуст, то надо вернуть первый элементы пары temp,   |           * если всё же temp не пуст, то надо вернуть первый элементы пары temp,   | ||
| − |           * в качестве left нового дека надо поставить temp.last (на уровне ниже, из которого он пришёл, temp хранил в два раза больше элементов | + |           * в качестве left нового дека надо поставить temp.last (на уровне ниже, из которого он пришёл,   | 
| − | + |          * temp хранил в два раза больше элементов, поэтому на текущем уровне temp.last будет соответствовать   | |
| + |          * как раз требуемому количеству элементов), newDeque делаем child'ом | ||
|           * нового дека, а right текущего, right'ом нового |           * нового дека, а right текущего, right'ом нового | ||
|           */ |           */ | ||
Версия 15:51, 10 марта 2012
| Определение: | 
| Дек (англ. deque — double ended queue — очередь с двумя концами) — структура данных с двусторонним доступом к элементам, т. е. их можно удалять и добавлять как в начало, так и в конец дека. | 
Кроме дека ещё существует структура данных, называемая steque, которая представляет собой объединение стека и очереди - элементы можно добавлять только в один конец, а извлекать можно с обоих.
Эффективная реализация
Написать дек на массиве не представляет особого труда, зная уже, как работают стек и очередь. Далее будет приведена реализация операций добавление элемента и извлечение из одного конца дека за истинное время работы Добавление и исключение из другого конца делается симметрично.
Персистентный дек можно визуально представить как дерево, где каждый узел хранит пару - левый элемент и правый, а также ребёнка - ссылку на следующий дек. Только с каждым уровнем вложенности левый и правый элемент хранят в два раза больше объектов, чем на предыдущем уровне.
Тип  хранит пару элементов  и  типов  и  соответственно.
Pair<> { };
Сам дек можно инициализировать напрямую, вызвав конструктор , или через шаблоны , тогда произойдёт следующее
Deque<Pair<>> { left; right; Deque<Pair<Pair<>, Pair<>> child; };
Таким образом, элементы с начала хранятся в левой ветке дерева, а с конца - в правой.
Наша структура данных персистентна, следовательно операция  возвращает новый дек , c элементом  в начале.
push_front(x) if left == // если левый ребенок не существует, то сделаем его новым элементом return Deque(x, child, right) else // иначе объеденим его с новым элементов и попытаемся добавить в дек на следующем уровне return Deque(, child.push_front(Pair<x, left>), right)
Метод  возвращает пару  из первого элемента и нового дека, полученного из старого изъятием этого элемента.
pop_front() if left // если левый ребёнок не пуст, то возвращаем пару из него и нового дека без левого ребёнка return left, Deque(, child, right) else if child == // если левый ребёнок оказался пуст, и при этом ссылка на следующий дек тоже отсутсвует, // значит, вернём пару из правого ребёнка и абсолютно пустого дека return right, Deque() else /* * если два предыдущих условия оказались невыполнены, то мы рекурсивно вызываем метод pop_front() * и возвращённую пару "элемент-новый дек" сохраняем в переменные temp & newDeque * Рекурсивные вызовы прекратятся, как только левый ребёнок окажется существующим * или в деке будет отсутствовать ссылка на следущий дек */ temp, newDeque child.pop_front() if temp == /* * это возможно только в случае, когда в деке на максимальной глубине все элементы оказались пусты * значит мы сейчас на предпоследнем уровне, и левый ребёнок пустой, а child ссылается на абсолютно пустой дек, * поэтому мы возвращаем right текущего дека, и пустой дек */ return right, Deque() else /* * если всё же temp не пуст, то надо вернуть первый элементы пары temp, * в качестве left нового дека надо поставить temp.last (на уровне ниже, из которого он пришёл, * temp хранил в два раза больше элементов, поэтому на текущем уровне temp.last будет соответствовать * как раз требуемому количеству элементов), newDeque делаем child'ом * нового дека, а right текущего, right'ом нового */ return temp.first, Deque(temp.last, newDeque, right)
Чтобы извлечь элемент, придётся спуститься не больше, чем на глубину дерева. Аналогично для добавления. Поэтому обе операции выполняются за


