Prerequisites: Code snippets in this article is in typescript. Basic understanding of typescript and JavaScript are required. Linked List: You can go over these concepts in my previous article
Стек – это абстрактная структура данных, в которой хранится набор объектов в последнемпоследнем первом начале (ЛИФО) подход.
Это означает, что последний или недавний элемент, который мы добавляем в стек, является первым элементом, который мы сможем извлечь. Представьте, что вы складываете 10 книг друг на друга. Вы можете взять только верхнюю книгу из стопки, которая была добавлена недавно.
Ниже приведены основные функции, поддерживаемые любой реализацией стека:
- push:метод, позволяющий добавлять элементы данных в стек.
- pop: метод, позволяющий удалить элемент из стека. Это будет верхний элемент в стеке.
- Peek: метод, который позволит нам просмотреть верхний элемент стека, не удаляя его из стека. В некоторых реализациях для этого используется свойство top или first.
- size: свойство для хранения количества элементов в стеке. В некоторых реализациях это также называется Count или Length.
Теперь перейдем к деталям реализации. Стек может быть реализован многими способами. Один из способов — реализовать структуру данных Array. Мы можем добавлять элементы в конец массива и удалять их из конца массива. Но когда дело доходит до динамического изменения размера, массив менее эффективен. Итак, мы реализуем Stack, используя концепции связанных списков.
Определение класса элемента стека
Давайте начнем с создания класса, представляющего наш элемент стека. Это будет узел связанного списка, который позволит нам хранить данные и указатель на следующий элемент в нашей реализации стека с использованием связанного списка.
Определение класса стека
Класс стека будет иметь несколько свойств.
- first: свойство для хранения ссылки на первый/верхний/головной элемент в стеке.
- last: свойство для хранения ссылки на последний/хвостовой элемент в стеке.
- size: свойство для хранения подсчета общего количества элементов в стеке.
Все, что нам нужно сделать сейчас, это реализовать необходимые методы.
Толкать()
В этом методе мы добавим новый элемент в начало списка, что означает, что мы будем добавлять новый элемент в начало нашего связанного списка. Давайте посмотрим на пример здесь для лучшего понимания.
Step 1: Add a new node to the list with value 1 1 Step 2: Add another node to the list with value 2 2 → 1 Step 3: Add another node to the list with value 3 3 → 2 → 1
Обратите внимание, что все новые элементы, которые мы добавляем на каждом этапе, находятся в начале списка. Давайте напишем псевдокод для того же самого:
- Создайте метод push, который принимает число в качестве параметра.
- Создайте новый Element для переданного значения.
- Убедитесь, что размер стека равен нулю. Если это так, установите свойства first, last в стеке для нового элемента.
- Если нет, установите наш новый Element.next так, чтобы он указывал на первый элемент. Затем установите first для нового элемента.
- Увеличьте size на 1.
Теперь попробуйте написать код для метода push, прежде чем прокрутить вниз, чтобы увидеть мой.
Поп()
В этом методе мы удалим первый/верхний элемент из стека. Это означает, что мы должны удалить заголовок нашего связанного списка. Давайте посмотрим на пример здесь для лучшего понимания.
Step 1: Let's start with this stack 3 → 2 → 1 Step 2: Pop an element from the stack. We will return 3 and set 2 as the first element. 2 → 1 Step 3: Pop an element form the stack. We will return 2 and set 1 as the first element. 1
Обратите внимание, что мы удаляем элемент из начала списка. Давайте теперь посмотрим на псевдокод этого метода:
- Создайте новый метод с именем pop(), который будет возвращать число.
- Убедитесь, что размер стека size равен нулю. Если это так, верните ноль.
- Если в нашем стеке есть элементы, сохраните значение первого элемента во временной переменной с именем prevFirst.
- Установите элемент first как prevFirst.next.
- Удалите prevFirst из стека, установив для prevFirst.next значение null
- Верните элемент prevFirst.
Вот и все. Мы сделали. Посмотрим, сможешь ли ты это закодировать. Ниже приведен код:
заглянуть()
Это проще всего. Все, что нам нужно сделать, это вернуть значение нашего свойства first, которое мы постоянно обновляли при выполнении операций push и pop. Итак, давайте перейдем непосредственно к коду.
peek() : number { if(this._size === 0) return null; return this._first; }
Большой O из стека
Стек — одна из самых эффективных структур данных, которую вы можете найти, если все, что вам нужно делать, это добавлять элементы и удалять элементы сверху.
Вставка/удаление:по свойствам стека, LIFO; и мы реализуем стек, используя связанный список, большой O для этих операций всегда O(1). Это связано с тем, что добавление/удаление элемента из головы связанного списка всегда занимает всего 1 операцию.
Доступ/Поиск. Чтобы найти элемент по определенному индексу или проверить, существует ли элемент в стеке, мы должны линейно просмотреть все элементы. Из-за этого эти операции имеют большой O из O(n).
Я надеюсь, что это дало вам понимание концепций стека и его временной сложности. Вы можете найти весь код здесь, на GitHub, где есть код на машинописном языке и C#. Хлопайте и делитесь, если вам это нравится.
Далее: Реализация очереди