Реализация очереди требует больше памяти чем стек

Преимущества и недостатки при реализации стека, очереди и дека через дин. массива

Доброго времени суток!

1) Назовите преимущества и недостатки реализации очереди с помощью динамического массива.
2) Назовите преимущества и недостатки реализации стека с помощью односвязного списка.
3) Назовите преимущества и недостатки реализации дека с помощью динамического массива.

1) По первому я могу лишь предположить, что будет долгое время работы в связи с тем, что необходимо будет довыделять буфер, если вдруг закончится место в массиве. Да и в принципе достаточно долго доставать элемент, если он находится в конце.
2) Ничего не придумал
3) ничего не придумал

Если есть идеи, подкиньте пожалуйста. Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

Добавлено через 1 час 41 минуту
UPD:

1) Достоинсва: можно не заботится, о том, что закончится память, можно быстро найти нужный элемент(например бинарным поиском если очередь отсортирована. В отличии от очереди реализованной на затрачивает меньше памяти.
Недостатки: большое время добавления элемента, если заканчивается память(из-за того, что необходима скопировать весь массив в новый буфер.
2) Достоинства: Добавление элемента всегда работает за одно и тоже время(т.к. нет необходимости компировать весь стек, если вдруг кончится память),
Недостатки: Возможность перемещаться по стеку лишь в одном направлении, что затруднит поиск необхоимого элемента, элементы списка могут располагаться в памяти разреженно, что оказывает негативный эффект на кэширование процессора.
3)Достоинства: Занимает меньше памяти, чем реализация дека с помощью списка
Недостатки: Сложнее добавлять новые элементы если реализовывать не списком.

Наверняка ещё есть что-то, но вроде должно хватить. Если что добавьте потом.

Модератор закройте тему.
Всегда хотел это сказать. Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

Источник

Алгоритмы и структуры данных для начинающих: стеки и очереди

Авторизуйтесь

Алгоритмы и структуры данных для начинающих: стеки и очереди

Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

В предыдущих частях мы рассматривали базовые структуры данных, которые, по сути, являлись надстройками над массивом. В этой статье мы добавим к коллекциям простые операции и посмотрим, как это повлияет на их возможности.

Стек — это коллекция, элементы которой получают по принципу «последний вошел, первый вышел» (Last-In-First-Out или LIFO). Это значит, что мы будем иметь доступ только к последнему добавленному элементу.

10–12 декабря, Онлайн, Беcплатно

Наиболее часто встречающаяся аналогия для объяснения стека — стопка тарелок. Вне зависимости от того, сколько тарелок в стопке, мы всегда можем снять верхнюю. Чистые тарелки точно так же кладутся на верх стопки, и мы всегда будем первой брать ту тарелку, которая была положена последней.

Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

Если мы положим, например, красную тарелку, затем синюю, а затем зеленую, то сначала надо будет снять зеленую, потом синюю, и, наконец, красную. Главное, что надо запомнить — тарелки всегда ставятся и на верх стопки. Когда кто-то берет тарелку, он также снимает ее сверху. Получается, что тарелки разбираются в порядке, обратном тому, в котором ставились.

Теперь, когда мы понимаем, как работает стек, введем несколько терминов. Операция добавления элемента на стек называется «push», удаления — «pop». Последний добавленный элемент называется верхушкой стека, или «top», и его можно посмотреть с помощью операции «peek». Давайте теперь посмотрим на заготовку класса, реализующего стек.

Класс Stack

Метод Push

Поскольку мы используем связный список для хранения элементов, можно просто добавить новый в конец списка.

Метод Pop

Push добавляет элементы в конец списка, поэтому забирать их будет также с конца. В случае, если список пуст, будет выбрасываться исключение.

Метод Peek

Метод Count

Зачем нам знать, сколько элементов находится в стеке, если мы все равно не имеем к ним доступа? С помощью этого поля мы можем проверить, есть ли элементы на стеке или он пуст. Это очень полезно, учитывая, что метод Pop кидает исключение.

Пример: калькулятор в обратной польской записи

Классический пример использования стека — калькулятор в обратной польской, или постфиксной, записи. В ней оператор записывается после своих операндов. То есть, мы пишем:

Другими словами, вместо «4 + 2» мы запишем «4 2 +». Если вам интересно происхождение обратной польской записи и ее названия, вы можете узнать об этом на Википедии или в поисковике.

То, как вычисляется обратная польская запись и почему стек так полезен при ее использовании, хорошо видно из следующего алгоритма:

То есть, для выражения «4 2 +» действия будут следующие:

В конце на стеке окажется одно значение — 6.

Очередь

Очереди очень похожи на стеки. Они также не дают доступа к произвольному элементу, но, в отличие от стека, элементы кладутся (enqueue) и забираются (dequeue) с разных концов. Такой метод называется «первый вошел, первый вышел» (First-In-First-Out или FIFO). То есть забирать элементы из очереди мы будем в том же порядке, что и клали. Как реальная очередь или конвейер.

Очереди часто используются в программах для реализации буфера, в который можно положить элемент для последующей обработки, сохраняя порядок поступления. Например, если база данных поддерживает только одно соединение, можно использовать очередь потоков, которые будут, как ни странно, ждать своей очереди на доступ к БД.

Класс Queue

Метод Enqueue

Новые элементы очереди можно добавлять как в начало списка, так и в конец. Важно только, чтобы элементы доставались с противоположного края. В данной реализации мы будем добавлять новые элементы в начало внутреннего списка.

Метод Dequeue

Поскольку мы вставляем элементы в начало списка, убирать мы их будем с конца. Если список пуст, кидается исключение.

Метод Peek

Метод Count

Двусторонняя очередь

Двусторонняя очередь (Double-ended queue), или дек (Deque), расширяет поведение очереди. В дек можно добавлять или удалять элементы как с начала, так и с конца очереди. Такое поведение полезно во многих задачах, например, планирование выполнения потоков или реализация других структур данных. Позже мы рассмотрим вариант реализации стека с помощью двусторонней очереди.

Класс Deque

Метод EnqueueFirst

Метод EnqueueLast

Метод DequeueFirst

Метод DequeueLast

Метод PeekFirst

Метод PeekLast

Метод Count

Пример: реализация стека

Двусторонняя очередь часто используется для реализации других структур данных. Давайте посмотрим на пример реализации стека с ее помощью.

У вас, возможно, возник вопрос, зачем реализовывать стек на основе очереди вместо связного списка. Причины две: производительность и повторное использование кода. У связного списка есть накладные расходы на создание узлов и нет гарантии локальности данных: элементы могут быть расположены в любом месте памяти, что вызывает большое количество промахов и падение производительности на уровне процессоров. Более производительная реализация двусторонней очереди требует массива для хранения элементов.

Тем не менее, реализация стека или очереди с помощью массива — непростая задача, но такая реализация двусторонней очереди и использование ее в качестве основы для других структур данных даст нам серьезный плюс к производительности и позволит повторно использовать код. Это снижает стоимость поддержки.

Позже мы посмотрим на вариант очереди с использованием массива, но сначала давайте взглянем на класс стека с использованием двусторонней очереди:

Хранение элементов в массиве

Как уже было упомянуто, у реализации очереди с использованием массива есть свои преимущества. Она выглядит простой, но на самом деле есть ряд нюансов, которые надо учесть.

Давайте посмотрим на проблемы, которые могут возникнуть, и на их решение. Кроме того, нам понадобится информация об увеличении внутреннего массива из прошлой статьи о динамических массивах.

При создании очереди у нее внутри создается массив нулевой длины. Красные буквы «h» и «t» означают указатели _head и _tail соответственно.

Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

Добавляем элемент в начало

Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

Добавляем элемент в конец

Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

Добавляем еще один элемент в начало

Обратите внимание: индекс «головы» очереди перескочил в начало списка. Теперь первый элемент, который будет возвращен при вызове метода DequeueFirst — 0 (индекс 3).

Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

И еще один в конец

Массив заполнен, поэтому при добавлении элемента произойдет следующее:

Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

Добавляем значение в конец расширенного массива

Теперь посмотрим, что происходит при удалении элемента:

Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

Удаляем элемент из начала

Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

Удаляем элемент с конца

Ключевой момент: вне зависимости от вместимости или заполненности внутреннего массива, логически, содержимое очереди — элементы от «головы» до «хвоста» с учетом «закольцованности». Такое поведение также называется «кольцевым буфером».

Теперь давайте посмотрим на реализацию.

Класс Deque (с использованием массива)

Интерфейс очереди на основе массива такой же, как и в случае реализации через связный список. Мы не будем его повторять. Однако, поскольку список был заменен на массив, у нас добавились новые поля — сам массив, его размер и указатели на «хвост» и «голову» очереди.

Алгоритм роста

Когда свободное место во внутреннем массиве заканчивается, его необходимо увеличить, скопировать элементы и обновить указатели на «хвост» и «голову». Эта операция производится при необходимости во время добавления элемента. Параметр startingIndex используется, чтобы показать, сколько полей в начале необходимо оставить пустыми (в случае добавления в начало).

Обратите внимание на то, как извлекаются данные, когда приходится переходить в начало массива при проходе от «головы» к «хвосту».

Метод EnqueueFirst

Метод EnqueueLast

Метод DequeueFirst

Метод DequeueLast

Метод PeekFirst

Метод PeekLast

Метод Count

Продолжение следует

Вот мы и закончили четвертую часть нашего цикла статей. В ней мы рассмотрели стеки и очереди. В следующий раз мы перейдем к бинарным деревьям поиска.

Источник

Стек, очередь и куча

На рисунке вы можете видеть обобщенную модель организации памяти компьютера.

Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

Стек — это область памяти, которую вы, как программист, не контролируете никоим образом. В неё записываются переменные и информация, которые создаются в результате вызова любых функций. Когда функция заканчивает работу, то вся информация о ее вызов и ее переменные удаляются из стека автоматически.

Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

Но важнее даже не это, а то, что стек — это структура данных, которая работает по принципу «последним пришел — первым ушел» (last in first out, LIFO). На лекции Дэвид предложил представление стека, как стопки подносов в столовой. Поднос, который попал в стопку последним, новый клиент столовой возьмет в первую очередь.

Над стеком можно осуществлять две операции: push (занесение данных) и pop (изъятие данных).

Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

Пример реализации стека языке С приведен ниже. В этом примере, стек — это просто массив строк, имеет определенную емкость (CAPACITY), и текущий размер (size):

Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

Для реализации операции pop, необходимо проверить, не пустой стек, уменьшить текущий размер на единицу и вернуть элемент.

Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

Очередь

Очередь (queue) — это структура данных, которая напоминает обычную очередь. То есть, в отличие от стека, она работает по принципу «первым пришел — первым ушел» (first in first out, FIFO).

Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

Для очереди определены две операции: добавление элемента в конец очереди (enqueue) и изъятие элемента с начала очереди (dequeue).

Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

В примере объявлена очередь, которая, по сути, представляет собой массив строк:

Чтобы реализовать операцию enqueue, необходимо убедиться, что очередь, не переполнена, добавить элемент в конец очереди и увеличить текущий размер на единицу.

Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

Чтобы реализовать операцию dequeue, надо убедиться, что очередь не пуста, увеличить head на единицу, уменьшить текущий размер и вернуть первый элемент очереди.

Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

Куча и переполнение буфера

Куча (heap) — область памяти, которую контролируют непосредственно программисты. Над которой вы, как программисты, получаете непосредственный контроль. Память здесь выделяется в результате вызова функции malloc.

Более глубокие знания о стеке и куче вам пока не понадобятся. Вы их получите позже, если захотите изучать программирование и компьютерные науки глубже.

Буфер — это массив определенной длины, расположенный в памяти. Переполнение буфера (buffer overflow) возникает, если мы пытаемся записать в него больше данных, чем предусмотрено размером этого массива. С помощью переполнения буфера злоумышленник может записать опасный код в память компьютера.

Источник

Как и зачем делать очередь на двух стеках

Данный пост написан для новичков в олимпиадном программировании и начинающих разработчиков, готовящихся к прохождению алгоритмических интервью. В конце бонусная задачка. Если заинтересовал, прошу под кат 🙂

Для начала вспомним основы:

Стек реализует принцип LIFO (англ. last in — first out, «последним пришёл — первым вышел»).

Стек имеет две основные операции:

Очередь

Очередь — это структура данных с доступом к элементам FIFO (англ. First In, First Out – «первым пришёл — первым ушёл»)

Очередь имеет два основных метода в своем интерфейсе:

Обычно рассматривают два базовых подхода к реализации очереди:

Почему стек круче, чем очередь

Представим себе, что наша структура данных должна поддерживать следующий набор операций:

Для стека можно очень просто поддерживать любую из приведенных операций: достаточно хранить на его вершине пару:

Реализация очереди требует больше памяти чем стек. Смотреть фото Реализация очереди требует больше памяти чем стек. Смотреть картинку Реализация очереди требует больше памяти чем стек. Картинка про Реализация очереди требует больше памяти чем стек. Фото Реализация очереди требует больше памяти чем стек

, где второй элемент пары — результат операции, примененной ко всем элементам стека.

Ниже пример реализации стека с поддержкой минимума на Python:

А теперь подумайте, как проделать тот же фокус с очередью? Если пробовать с классической очередью, организованной на массиве, вряд ли что-то получится. Это связано с тем, что операция минимум не имеет обратную операцию (как операция сложения имеет операцию вычитания, например). Как вы могли догадаться, далее я расскажу о не совсем классической реализации очереди на двух стеках.

Очередь на двух стеках

Главное условие, которое должно быть выполнено — все операции должны выполняться за амортизированное O(1).

Возьмем два стека: s1 и s2.

Операцию push будем всегда делать в стек s1.

Операция pop будет устроена так: если стек s2 пустой, перекладываем все элементы из s1 в s2 последовательными вызовами pop и push. Теперь в стеке s2 лежат элементы в обратном порядке (самый верхний элемент — это самый первый положенный элемент в нашу очередь).

Если s2 не пуст, тупо достаем элементы из него. Как только s2 окажется снова пустым повторяем ту же операцию.

Время работы

Операция push: Мы тупо кладем элемент в стек s1. Время работы O(1).

Операция pop: Для каждого элемента мы делаем не более одного перекладывания из стека в стек, следовательно амортизированное время работы составит O(1).

Операция get_min: Для стеков s1 и s2 известны минимумы, поэтому мы просто берем минимум из минимумов. Время работы O(1).

Бонусная задачка

Заключение

Спасибо, что дочитали до конца!

Если вас заинтересовала тема, можете почитать как сделать персистентную очередь на двух стеках здесь, либо дождаться выхода следующего моего топика.

Пишите в комментариях какие задачи на двух стеках вам приходилось решать на интервью или контестах.

Источник

Простейшие структуры данных: стек, очередь, дек

Понятие структуры данных

Чаще всего данные, с которыми работают программы, хранятся во встроенных в используемый язык программирования массивах, константной или переменной длины. Массив константной длины можно назвать простейшей структурой данных. Но иногда для решения задачи требуется большая эффективность некоторых операций, чем у массива. В таких случаях используются другие структуры данных, часто гораздо более сложные.

Таким образом, структура данных характеризуется операциями, которые она может выполнять, и скоростью их выполнения.

В качестве примера рассмотрим несколько простейших структур данных, которые не предоставляют выгоды в эффективности, но имеют чётко определённый набор поддерживаемых операций.

Для объяснения принципа работы стека часто используется аналогия со стаканом с печеньем. Представьте, что на дне вашего стакана лежат несколько кусков печенья. Вы можете положить наверх ещё один кусок или достать уже находящийся наверху. Остальные куски закрыты верхним, и вы про них ничего не знаете. Для описания стека часто используется аббревиатура LIFO (Last In, First Out), подчёркивающая, что элемент, попавший в стек последним, первым будет из него извлечён.

Приведём простую реализацию стека на C++. Для простоты максимальный размер нашего стека будет ограничен тысячей элементов:

Как видите, для реализации стека хватает одного массива и одного указателя, обозначающего крайний элемент.

Очередь

Очередь поддерживает тот же набор операций, что и стек, но имеет противоположную семантику. Для описания очереди используется аббревиатура FIFO (First In, First Out), так как первым из очереди извлекается элемент, раньше всех в неё добавленный. Название этой структуры говорит само за себя: принцип работы совпадает с обычными очередями в магазине или на почте.

Реализация очереди похожа на реализацию стека, но в этот раз нам понадобятся два указателя: для первого элемента очереди (“головы”) и последнего (“хвоста”):

При такой реализации очередь будет постепенно “ползти” вправо по выделенной области памяти (массиву), и достаточно быстро выйдет за её границы. Впрочем, эта реализация иллюстративная, на практике вы просто будете использовать уже готовую реализацию очереди из стандартной библиотеки (об этом ниже). В ней этот дефект отсутствует из-за более сложной работы с памятью.

В принципе мы можем реализовать её таким же способом, как и две предыдущих, но как и в случае с очередью, эта реализация будет далека от оптимальной.

Стек, очередь и дек в стандартной библиотеке C++

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

Более сложные структуры данных

Приведённый выше материал мог вызвать у вас лёгкое недоумение и сомнения в целесообразности всех этих ограничений на обычные массивы. На самом деле, стек, очередь и дек являются лишь простейшими примерами структур данных, не предоставляющими выгоды в скорости выполнения операций. Серьёзным структурам данных посвящены отдельные темы. Стек, очередь и дек призваны проиллюстрировать, что главными характеристиками структуры данных являются набор поддерживаемых операций и скорость их выполнения.

brestprog

Олимпиадное программирование в Бресте и Беларуси

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *