Рубрики
Без рубрики

Как реализовать стеки и очереди в Python – Часть первая: Стеки

<< Неделя 0: Введение | Неделя 2: очереди >> Просмотреть решение на GitHub Я очень рекомендую… Tagged с Python, Codenewbie.

<< Неделя 0: Введение | Неделя 2: очереди >>

Просмотреть решение на GitHub

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

С понедельником, ребята! Мы начинаем серию о структурах данных и алгоритмах- каким сюрпризом- структурами данных! Стеки и очереди, если быть точными. Как и в большинстве проблем с доской, возможно, вам никогда не придется использовать их в промышленности, но это хороший способ показать, что вы знаете, как внедрить занятия-ака «сделать то, что делает то, что вы говорите, чтобы делать».

Концепция для стеков и очередей относительно проста. Стеки похожи на стопку пластин: вы всегда удаляете один на вершине, последний размещен. Вы услышите термин Lifo – Последнее в первом месте. Очерки – это как раз наоборот, первый пункт в первой убрать. Представьте себе очередь в Starbucks, первым клиентом, который всегда будет подан кофе (если они не заказали капельный кофе и сразу подают? Хм … игнорировать это).

IRL стек и очередь. ( Источники: InsideoutStyleblog.com, Koreatimes.co.kr)

Создание стека в Python

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

# Implement a stack that has the following methods:
# 1. push(item), which pushes an element onto the stack
# 2. pop(), which pops off and returns the topmost element of the stack. If there are no elements in the stack, then it should throw an error or return null.
# Each method should run in constant time.

Это начинается со слова «реализация», что означает, что они хотят класса. Если вы не привыкли работать с классами, они, по сути, план для объекта. Когда мы начинаем новый объект с классом Стек , он будет иметь все свойства и методы, которые мы определили при составлении класса.

Мы начнем с определения класса, а затем добавим __init__ метод Кроме того, мы добавим пустые методы pop () и push () Анкет Ключевое слово Пасс это просто так, что Python не расстроится, что у нас есть пустой метод.

class Stack:
    def __init__():
        pass

    def pop():
        pass

    def push():
        pass

Осторожно, теперь у нас есть Стек класс. Давайте определим __init__ Метод, который будет определять все свойства стека при инициализации. То есть каждый раз, когда родился новый стек, мы собираемся дать ему некоторые вещи. Любые идеи?

Стек по сути – это список (помните, что массивы называются «списками» в Python) с некоторыми специальными свойствами – вы можете добавить или удалить самый последний элемент. Итак, мы представляем это как список, который я позвоню стек Анкет Чтобы определить свойство класса в Python, мы будем использовать я ключевое слово. Чтобы получить доступ к этому ключевому слову, оно также должно быть передано в качестве аргумента методу.

def __init__(self):
    self.stack = []

Хорошо, давайте перейдем к push () метод Это также займет я Как аргумент, чтобы мы могли получить доступ к этому стек переменная Мы только что определили. Кроме того, это займет пункт , тот, который мы хотим добавить в верхнюю часть стека.

def push(self, item):
    pass

Чтобы добавить и убрать элементы из стека, мы представим конец списка как верх. Это облегчает ситуацию в Python, так как мы можем использовать .append () Метод для добавления элемента в конце списка, например, так:

def push(self, item):
    self.stack.append(item)

pop () Метод будет похожим. Python имеет .pop () Метод для списков, который удаляет окончательный элемент в списке. Удобный! Метод возвращает удаленный элемент, поэтому мы сохраним его в локальной переменной с именем удалено и вернуть его.

def pop(self):
    removed = self.stack.pop()
    return removed

НО ЖДАТЬ! У нас есть проблемы. Что если в стеке нет элементов для удаления? К счастью, подсказка дала нам мелкий шрифт, чтобы напомнить нам о этой потенциальной ловушке:

# If there are no elements in the stack, then it should throw an error or return null.

Таким образом, все, что нам нужно сделать, это добавить условное утверждение для проверки этого края. Для этого, прежде чем мы бежим .pop В списке мы просто добавим оператор IF, чтобы проверить, пуст ли стек. Единственный нулевой тип в Python – это Нет , поэтому мы вернем это в этом случае.

def pop(self):
    if len(self.stack) == 0:
        return None
    removed = self.stack.pop()
    return removed

И это все! Чтобы подтвердить:

stack.py

class Stack:
    def __init__(self):
        self.stack = []

    def push(self, item):
        self.stack.append(item)

    def pop(self):
        if len(self.stack) == 0:
            return None
        removed = self.stack.pop()
        return removed

Еще одна вещь, которую следует отметить, это то, что наше решение следует за ограничением, которое все методы работают в постоянное время, O (1). Это означает, что все они работают в одно и то же время независимо от длины стека. Если бы нам нужно было зацикливаться на списке, например, временная сложность была бы O (n), n – длина списка. Но мы этого не сделали, так что мы в порядке.

Тестирование нашего стека

Возможно, вы следили за Repl.it до сих пор и хорошей работы. Но вы заметите, если вы запустите программу, ничего не произойдет.

(Источник: imgur.com)

Как я уже сказал, классы похожи на чертежи для объекта. Мы сделали план, так что давайте проверим его, сделав объект. Вы можете сделать это из оболочки Python (вывод терминала в Repl.it) или в нижней части вашего файла Stack.py. Ради простоты, я называю свой стек s .

>>> s = Stack()

Теперь давайте проверим это красивое push () Метод, который мы написали, добавив несколько чисел в наш стек.

>>> s.push(1)
>>> s.push(2)
>>> s.push(3)

Если мы распечатаем S.Stack , мы должны получить [1, 2, 3] . Отлично. Итак, давайте попробуем pop () метод

>>> s.pop()

Теперь, если мы печатаем S.Stack , мы должны получить [1, 2] . Обратите внимание, как был удален только последний пункт, и значение 3 было возвращено. Но что произойдет, если мы продолжим удалять элементы? Мы можем проверить, вернется ли наш метод Нет Запустив одну и ту же команду еще несколько раз, а затем печатая возвращаемое значение.

>>> s.pop()
>>> s.pop()
>>> print(s.pop())

И там у вас есть стек, реализованный в Python. Вы официально выучили свою первую структуру данных.

Бонус: Интеграция max () метод

Образец, который я нашел, был, по -видимому, был задан на интервью Amazon, и он попросил дополнительный метод:

# 3. max(), which returns the maximum value in the stack currently. 
# If there are no elements in the stack, then it should throw an error or return null.

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

def __init__(self):
    self.stack = []
    self.max = None

Круто, теперь давайте обновим push () метод Есть два случая, которые нам нужно проверить:

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

В обоих случаях мы установим новый Макс значение для добавленного элемента. Таким образом, одна строка или Заявление сделает свое дело.

def push(self, item):
    self.stack.append(item)
    if len(self.stack) == 1 or item > self.max:
        self.max = item

Далее мы посмотрим на pop () Анкет Опять же, есть два случая, которые нам нужно проверить:

  1. Если удаляемый элемент является последним в стеке. Теперь, когда стек пуст, мы должны установить Макс к Нет Анкет
  2. Если удаляемый элемент равен значению максимального уровня, нам нужно пройти через список и найти новое значение.

Первый случай простой. После того, как мы позвоним .pop () В списке мы проверяем, не будет ли длина нулевой.

if len(self.stack) == 0:
    self.max = None

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

elif removed == self.max:
  self.max = self.stack[0]
  for value in self.stack:
    if value > self.max:
      self.max = value

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

def pop(self):
    if len(self.stack) == 0:
        return None
    removed = self.stack.pop()
    if len(self.stack) == 0:
        self.max = None
    elif removed == self.max:
        self.max = self.stack[0]
        for value in self.stack:
            if value > self.max:
                self.max = value
    return removed

Наконец, давайте внедрим max () Метод как рекламируется. Цель метода – просто вернуть Макс Значение, которое мы определили. Но вот в чем дело, в Python мы можем просто получить доступ к этому значению за пределами нашего определения класса, позвонив S.max Анкет Зачем нам написать целый метод, чтобы вернуть его?

Это еще одно удержание от объектно -ориентированного программирования в Java. Традиционно лучше всего поддерживать все наши переменные в частном порядке. Если вы строили, скажем, радио, вы бы не хотели, чтобы пользователи могли связываться с проводами внутри, только ручками и кнопками снаружи. В Java вы бы инициализировали это Макс Поле с ключевым словом Частный Анкет Тогда вы бы сделали метод под названием Максимум или get_max () Это возвращает это значение-в противном случае единственный способ получить к нему доступ.

Есть способ сделать переменные частными в Python, просто определите его с помощью двойного подчеркивания («Dunder» для вас, ботаников), как SO: __max Анкет Вам решать, хотите ли вы это сделать; На собеседовании лучшая практика – спросить вашего интервьюера, чего он хочет. Тот факт, что вы спрашиваете, означает, что вы яркие и проницательные, а затем вы можете дать им то, что они хотят.

Чтобы подтвердить:

stack.py

class Stack:
  def __init__(self):
    self.stack = []
    self.max = None

  def pop(self):
    if len(self.stack) == 0:
      return None
    removed = self.stack.pop()
    if len(self.stack) == 0:
      self.max = None
    elif removed == self.max:
      self.max = self.stack[0]
      for value in self.stack:
        if value > self.max:
          self.max = value
    return removed

  def push(self, item):
    self.stack.append(item)
    if len(self.stack) == 1 or item > self.max:
      self.max = item

  def get_max(self):
    return self.max

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

>>> s = Stack()
>>> s.push(1)
>>> s.push(2)
>>> s.push(3)
>>> s.max
3
>>> s.pop()
3
>>> s.max
2

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

<< Неделя 0: Введение | Неделя 2: очереди >>

Просмотреть решение на GitHub

Шеймус Хейккила ранее был ассистентом преподавателя в Генеральной Ассамблеи Сиэтл. Этот блог не связан с GA.

Оригинал: “https://dev.to/pythonwb/how-to-implement-stacks-and-queues-in-python-part-one-stacks-32f8”