<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=93.185.30.197&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=93.185.30.197&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/93.185.30.197"/>
		<updated>2026-06-10T08:30:28Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9E%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D1%8C&amp;diff=64864</id>
		<title>Очередь</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%9E%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D1%8C&amp;diff=64864"/>
				<updated>2018-04-08T08:26:54Z</updated>
		
		<summary type="html">&lt;p&gt;93.185.30.197: /* pop */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Определение ==&lt;br /&gt;
[[Файл: Fifo_new.png|right|150px]]&lt;br /&gt;
'''Очередь''' (англ. ''queue'')  {{---}} это структура данных, добавление и удаление элементов в которой происходит путём операций &amp;lt;tex&amp;gt; \mathtt{push} &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; \mathtt{pop} &amp;lt;/tex&amp;gt; соответственно. Притом первым из очереди удаляется элемент, который был помещен туда первым, то есть в очереди реализуется принцип «первым вошел — первым вышел» (англ. ''first-in, first-out {{---}} FIFO''). У очереди имеется '''голова''' (англ. ''head'') и '''хвост''' (англ. ''tail''). Когда элемент ставится в очередь, он занимает место в её хвосте. Из очереди всегда выводится элемент, который находится в ее голове. Очередь поддерживает следующие операции:&lt;br /&gt;
* &amp;lt;tex&amp;gt; \mathtt{empty} &amp;lt;/tex&amp;gt; {{---}} проверка очереди на наличие в ней элементов,&lt;br /&gt;
* &amp;lt;tex&amp;gt; \mathtt {push} &amp;lt;/tex&amp;gt; (запись в очередь) {{---}} операция вставки нового элемента,&lt;br /&gt;
* &amp;lt;tex&amp;gt; \mathtt{pop} &amp;lt;/tex&amp;gt; (снятие с очереди) {{---}} операция удаления нового элемента,&lt;br /&gt;
* &amp;lt;tex&amp;gt; \mathtt{size} &amp;lt;/tex&amp;gt; {{---}} операция получения количества элементов в очереди.&lt;br /&gt;
&lt;br /&gt;
== Реализация циклической очереди на массиве ==&lt;br /&gt;
Очередь, способную вместить не более &amp;lt;tex&amp;gt;\mathtt{n}&amp;lt;/tex&amp;gt; элементов, можно реализовать с помощью массива &amp;lt;tex&amp;gt;\mathtt{elements[0\dots n-1]}&amp;lt;/tex&amp;gt;. Она будет обладать следующими полями:&lt;br /&gt;
* &amp;lt;tex&amp;gt;\mathtt{head}&amp;lt;/tex&amp;gt; {{---}} голова очереди,&lt;br /&gt;
* &amp;lt;tex&amp;gt;\mathtt{tail}&amp;lt;/tex&amp;gt; {{---}} хвост очереди.&lt;br /&gt;
&lt;br /&gt;
=== empty ===&lt;br /&gt;
 '''boolean''' empty():&lt;br /&gt;
   '''return''' head == tail&lt;br /&gt;
&lt;br /&gt;
=== push ===&lt;br /&gt;
 '''function''' push(x : '''T'''):&lt;br /&gt;
   '''if''' (size() != n)&lt;br /&gt;
     elements[tail] = x&lt;br /&gt;
     tail = (tail + 1) % n&lt;br /&gt;
&lt;br /&gt;
=== pop ===&lt;br /&gt;
 '''T''' pop():&lt;br /&gt;
   '''if''' (empty()) &lt;br /&gt;
     '''return null'''&lt;br /&gt;
   x = elements[head]&lt;br /&gt;
   head = (head + 1) % n&lt;br /&gt;
   '''return''' x&lt;br /&gt;
&lt;br /&gt;
=== size ===&lt;br /&gt;
 '''int''' size()&lt;br /&gt;
   '''if''' head &amp;gt; tail&lt;br /&gt;
     '''return''' n - head + tail&lt;br /&gt;
   '''else'''&lt;br /&gt;
     '''return''' tail - head&lt;br /&gt;
Из-за того что нам не нужно снова выделять память, каждая операция выполняется за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt; времени.&lt;br /&gt;
&lt;br /&gt;
'''Плюсы:'''&lt;br /&gt;
* проста в разработке,&lt;br /&gt;
* по сравнению с реализацией на списке есть незначительная экономия памяти.&lt;br /&gt;
'''Минусы:'''&lt;br /&gt;
* количество элементов в очереди ограничено размером массива (исправляется написанием функции расширения массива),&lt;br /&gt;
* при переполнении очереди требуется перевыделение памяти и копирование всех элементов в новый массив.&lt;br /&gt;
&lt;br /&gt;
== Реализация на списке ==&lt;br /&gt;
Для данной реализации очереди необходимо создать [[Список | список]] &amp;lt;tex&amp;gt;list&amp;lt;/tex&amp;gt; и операции работы на созданном списке.&lt;br /&gt;
&lt;br /&gt;
Реализация очереди на односвязном списке:&lt;br /&gt;
=== List ===&lt;br /&gt;
* &amp;lt;code&amp;gt;ListItem(data : '''T''', next : '''ListItem''')&amp;lt;/code&amp;gt; {{---}} конструктор,&lt;br /&gt;
* &amp;lt;tex&amp;gt;\mathtt{x.value}&amp;lt;/tex&amp;gt; {{---}} поле, в котором хранится значение элемента,&lt;br /&gt;
* &amp;lt;tex&amp;gt;\mathtt{x.next}&amp;lt;/tex&amp;gt; {{---}} указатель на следующий элемент очереди.&lt;br /&gt;
&lt;br /&gt;
=== push ===&lt;br /&gt;
 '''function''' push(x : '''T'''):&lt;br /&gt;
   element = tail&lt;br /&gt;
   tail = ListItem(x, NULL)&lt;br /&gt;
   '''if''' size == 0&lt;br /&gt;
     head = tail&lt;br /&gt;
   '''else''' &lt;br /&gt;
     element.next = tail&lt;br /&gt;
   size++&lt;br /&gt;
&lt;br /&gt;
=== pop ===&lt;br /&gt;
 '''T''' pop(): &lt;br /&gt;
   size--&lt;br /&gt;
   element = head&lt;br /&gt;
   head = head.next&lt;br /&gt;
   '''return''' element&lt;br /&gt;
&lt;br /&gt;
=== empty ===&lt;br /&gt;
 '''boolean''' empty():&lt;br /&gt;
   '''return''' head == tail&lt;br /&gt;
[[Файл: Queue.png|right|230px]]&lt;br /&gt;
&lt;br /&gt;
'''Плюсы:'''&lt;br /&gt;
* каждая операция выполняется за время &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
'''Минусы:'''&lt;br /&gt;
* память фрагментируется гораздо сильнее и последовательная итерация по такой очереди может быть ощутимо медленнее, нежели итерация по очереди реализованной на массиве.&lt;br /&gt;
&lt;br /&gt;
== Реализация на двух стеках ==&lt;br /&gt;
Очередь можно реализовать на двух [[Стек|стеках]] &amp;lt;tex&amp;gt;\mathtt{leftStack}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\mathtt{rightStack}&amp;lt;/tex&amp;gt;. Поступим следующим образом: &amp;lt;tex&amp;gt;\mathtt{leftStack}&amp;lt;/tex&amp;gt; будем использовать для операции &amp;lt;tex&amp;gt; \mathtt {push} &amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\mathtt{rightStack}&amp;lt;/tex&amp;gt; для операции &amp;lt;tex&amp;gt; \mathtt{pop} &amp;lt;/tex&amp;gt;. При этом, если при попытке извлечения элемента из &amp;lt;tex&amp;gt;\mathtt{rightStack}&amp;lt;/tex&amp;gt; он оказался пустым, просто перенесем все элементы из &amp;lt;tex&amp;gt;\mathtt{leftStack}&amp;lt;/tex&amp;gt; в него (при этом элементы в &amp;lt;tex&amp;gt;\mathtt{rightStack}&amp;lt;/tex&amp;gt; получатся уже в обратном порядке, что нам и нужно для извлечения элементов, а &amp;lt;tex&amp;gt;\mathtt{leftStack}&amp;lt;/tex&amp;gt; станет пустым).&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tex&amp;gt; \mathtt{pushLeft} &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; \mathtt{pushRight} &amp;lt;/tex&amp;gt; {{---}} функции, реализующие операцию &amp;lt;tex&amp;gt; \mathtt{push} &amp;lt;/tex&amp;gt; для соответствующего стека,&lt;br /&gt;
* &amp;lt;tex&amp;gt; \mathtt{popLeft} &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; \mathtt{popRight} &amp;lt;/tex&amp;gt; {{---}} аналогично операции &amp;lt;tex&amp;gt; \mathtt {pop} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== push ===&lt;br /&gt;
 '''function''' push(x : '''T'''):&lt;br /&gt;
   pushLeft(x)&lt;br /&gt;
=== pop ===&lt;br /&gt;
 '''T''' pop():&lt;br /&gt;
   '''if''' '''not''' rightStack.empty()&lt;br /&gt;
     '''return''' popRight() &lt;br /&gt;
   '''else'''&lt;br /&gt;
     '''while''' '''not''' leftStack.empty()&lt;br /&gt;
       pushRight(popLeft())&lt;br /&gt;
     '''return''' popRight()&lt;br /&gt;
&lt;br /&gt;
При выполнении операции &amp;lt;tex&amp;gt; \mathtt{push} &amp;lt;/tex&amp;gt; будем использовать три монеты: одну для самой операции, вторую в качестве резерва на операцию &amp;lt;tex&amp;gt; \mathtt{pop} &amp;lt;/tex&amp;gt; из первого стека, третью во второй стек на финальный &amp;lt;tex&amp;gt; \mathtt{pop} &amp;lt;/tex&amp;gt;. Тогда для операций &amp;lt;tex&amp;gt; \mathtt{pop} &amp;lt;/tex&amp;gt; учётную стоимость можно принять равной нулю и использовать для операции монеты, оставшиеся после операции &amp;lt;tex&amp;gt; \mathtt{push} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Таким образом, для каждой операции требуется &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt; монет, а значит, амортизационная стоимость операций &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Плюсы:'''&lt;br /&gt;
* эту реализацию несложно модифицировать для получения минимума в текущей очереди за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
'''Минусы:'''&lt;br /&gt;
* если &amp;lt;tex&amp;gt;\mathtt{leftStack}&amp;lt;/tex&amp;gt; не пуст, то операция &amp;lt;tex&amp;gt; \mathtt{pop} &amp;lt;/tex&amp;gt; может выполняться &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени, в отличии от других реализаций, где &amp;lt;tex&amp;gt; \mathtt{pop} &amp;lt;/tex&amp;gt; всегда выполняется за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Реализация на шести стеках ==&lt;br /&gt;
&lt;br /&gt;
Одним из минусов реализации на двух стеках является то, что в худшем случае мы тратим &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени на операцию. Если распределить время, необходимое для перемещения элементов из одного стека в другой, по операциям, мы получим очередь без худших случаев с &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt; истинного времени на операцию.&lt;br /&gt;
&lt;br /&gt;
Подробное описание в статье [[Персистентная очередь#Реализация очереди на шести стеках|Персистентная очередь]].&lt;br /&gt;
&lt;br /&gt;
=== Отличия от других реализаций ===&lt;br /&gt;
&lt;br /&gt;
'''Плюсы:'''&lt;br /&gt;
* &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt; реального времени на операцию,&lt;br /&gt;
* возможность дальнейшего улучшения до [[Персистентная очередь|персистентной очереди]], если использовать [[Персистентный стек|персистентные стеки]]. &lt;br /&gt;
&lt;br /&gt;
'''Минусы:'''&lt;br /&gt;
* дольше в среднем выполняются операции,&lt;br /&gt;
* больше расход памяти,&lt;br /&gt;
* большая сложность реализации.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Стек]]&lt;br /&gt;
* [[Персистентная очередь]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* [[wikipedia:ru:Очередь_(программирование)|Википедия {{---}} Очередь (программирование)]]&lt;br /&gt;
* Т. Кормен. «Алгоритмы. Построение и анализ» второе издание, Глава 10.1, стр. 262&lt;br /&gt;
* T. H. Cormen. «Introduction to Algorithms» third edition, Chapter 10.1, p. 262&lt;br /&gt;
* [http://hdl.handle.net/1813/6273 ''Hood R., Melville R.'' Real Time Queue Operations in Pure LISP. {{---}} Cornell University, 1980]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Амортизационный анализ]]&lt;/div&gt;</summary>
		<author><name>93.185.30.197</name></author>	</entry>

	</feed>