Стек

В этой статье вы узнаете, что такое стек и как его реализовать в Python, Java и C/C++.

Стек — полезная структура данных. Она похожа на стопку тарелок, сложенных друг на друга.

Что можно сделать со стопкой тарелок?

  • Положить сверху еще одну тарелку.
  • Убрать верхнюю тарелку.

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

LIFO — принцип стека

Для стека доступны две операции — push и pop. push — помещение элемента в начало стека, pop — удаление.

Как видите, хоть элемент 3 и был добавлен последним, но удаляется он самым первым — так работает принцип LIFO.

Реализовать стек можно в любом языке — С, С++, Java, Python или C#. Во всех языках стеки очень похожи.

Базовые операции со стеком

Стек — объект (абстрактный тип данных), он поддерживает следующие операции:

  • Push — позволяет «протолкнуть» элемент в начало стека. 
  • Pop — позволяет удалить элемент из начала стека.
  • IsEmpty — проверяет, пуст ли стек.
  • IsFull — проверяет, заполнен ли стек.
  • Peek — позволяет получить элемент в начале стека без его удаления.

Как работает стек

Стек работает следующим образом:

  1. Указатель TOP используется для отслеживания «верхнего» элемента стека.
  2. После инициализации стека его значение равно -1. Так можно легко проверить заполненность стека: если TOP == -1, стек пуст.
  3. Когда мы «проталкиваем» элемент, значение TOP увеличивается на единицу. Следующий элемент будет находиться на позиции TOP+1.
  4. Когда мы используем метод pop, мы удаляем элемент, на который указывает TOP. После этого его значение уменьшается на единицу.
  5. Перед добавлением нового элемента мы проверяем, не заполнен ли стек.
  6. Перед удалением мы проверяем, не пуст ли стек.

Реализация стека

Наиболее распространенная реализация стека — массив. Но можно использовать и списки.

Python

# Реализация стека в python

# Создаем стек
def create_stack():
    stack = []
    return stack

# Создаем пустой стек
def check_empty(stack):
    return len(stack) == 0

# Добавляем элементы в стек
def push(stack, item):
    stack.append(item)
    print("Добавлен элемент: " + item)

# Удаляем элементы из стека
def pop(stack):
    if (check_empty(stack)):
        return "Стек пуст"

    return stack.pop()

stack = create_stack()
push(stack, str(1))
push(stack, str(2))
push(stack, str(3))
push(stack, str(4))
print("Удаленный элемент: " + pop(stack))
print("Стек после добавления элемента: " + str(stack))

Java

// Реализация стека в Java

class Stack {
  private int arr[];
  private int top;
  private int capacity;

  // Создаем стек
  Stack(int size) {
    arr = new int[size];
    capacity = size;
    top = -1;
  }

  // Добавляем элементы в стек
  public void push(int x) {
    if (isFull()) {
      System.out.println("Переполнение\nПрограмма остановлена\n");
      System.exit(1);
    }

    System.out.println("Добавлен элемент " + x);
    arr[++top] = x;
  }

  // Удаляем элементы из стека
  public int pop() {
    if (isEmpty()) {
      System.out.println("Стек пуст");
      System.exit(1);
    }
    return arr[top--];
  }

  // Функция возвращает размер стека
  public int size() {
    return top + 1;
  }

  // Проверяем, пуст ли стек
  public Boolean isEmpty() {
    return top == -1;
  }

  // Проверяем, не заполнен ли стек
  public Boolean isFull() {
    return top == capacity - 1;
  }

  public void printStack() {
    for (int i = 0; i <= top; i++) {
      System.out.println(arr[i]);
    }
  }

  public static void main(String[] args) {
    Stack stack = new Stack(5);

    stack.push(1);
    stack.push(2);
    stack.push(3);
    stack.push(4);

    stack.pop();
    System.out.println("\nПосле удаления");

    stack.printStack();

  }
}

С

// Реализация стека в C

#include <stdio.h>
#include <stdlib.h>

#define MAX 10

int count = 0;

// Создаем стек
struct stack {
  int items[MAX];
  int top;
};
typedef struct stack st;

void createEmptyStack(st *s) {
  s->top = -1;
}

// Проверяем, не заполнен ли стек
int isfull(st *s) {
  if (s->top == MAX - 1)
    return 1;
  else
    return 0;
}

// Проверяем, не пуст ли стек
int isempty(st *s) {
  if (s->top == -1)
    return 1;
  else
    return 0;
}

// Добавляем элементы в стек
void push(st *s, int newitem) {
  if (isfull(s)) {
    printf("Стек заполнен");
  } else {
    s->top++;
    s->items[s->top] = newitem;
  }
  count++;
}

// Удаляем элементы из стека
void pop(st *s) {
  if (isempty(s)) {
    printf("\n Стек пуст \n");
  } else {
    printf("Удален элемент= %d", s->items[s->top]);
    s->top--;
  }
  count--;
  printf("\n");
}

// Выводим в консоль элементы стека
void printStack(st *s) {
  printf("Стек: ");
  for (int i = 0; i < count; i++) {
    printf("%d ", s->items[i]);
  }
  printf("\n");
}

// Функция main
int main() {
  int ch;
  st *s = (st *)malloc(sizeof(st));

  createEmptyStack(s);

  push(s, 1);
  push(s, 2);
  push(s, 3);
  push(s, 4);

  printStack(s);

  pop(s);

  printf("\nПосле удаления\n");
  printStack(s);
}

C++

// Реализация стека в C++

#include <stdlib.h>
#include <iostream>

using namespace std;

#define MAX 10
int size = 0;

// Создаем стек
struct stack {
  int items[MAX];
  int top;
};
typedef struct stack st;

void createEmptyStack(st *s) {
  s->top = -1;
}

// Проверяем, не заполнен ли стек
int isfull(st *s) {
  if (s->top == MAX - 1)
    return 1;
  else
    return 0;
}

// Проверяем, не пуст ли стек
int isempty(st *s) {
  if (s->top == -1)
    return 1;
  else
    return 0;
}

// Добавляем элемент в стек
void push(st *s, int newitem) {
  if (isfull(s)) {
    printf("Стек заполнен");
  } else {
    s->top++;
    s->items[s->top] = newitem;
  }
  size++;
}

// Удаляем элемент из стека
void pop(st *s) {
  if (isempty(s)) {
    printf("\n Стек пуст \n");
  } else {
    printf("Удален элемент= %d", s->items[s->top]);
    s->top--;
  }
  size--;
  cout << endl;
}

// Выводим в консоль элементы стека
void printStack(st *s) {
  printf("Стек: ");
  for (int i = 0; i < size; i++) {
    cout << s->items[i] << " ";
  }
  cout << endl;
}

// Функция main
int main() {
  int ch;
  st *s = (st *)malloc(sizeof(st));

  createEmptyStack(s);

  push(s, 1);
  push(s, 2);
  push(s, 3);
  push(s, 4);

  printStack(s);

  pop(s);

  cout << "\nПосле удаления\n";
  printStack(s);
}

Временная сложность стека

У стеков, реализованных с помощью массива, скорость выполнения операций pop и push одинакова и равна O(1).

Где применяются стеки

  • Поворот слова задом-наперед. Поместите все буквы в стек и верните их — благодаря LIFO слово «отзеркалится».
  • В компиляторах. Компиляторы используют стеки для вычисления выражений вроде 2 + 4 / 5 * (7 - 9). Происходит это благодаря его конвертации в префиксную и постфиксную форму. 
  • В браузерах. Кнопка «Назад» хранит в стеке все URL-адреса, которые вы посещали. Каждый раз, когда вы посещаете новую страницу, ее URL-адрес оказывается на «вершине» стека. После нажатия на кнопку «Назад» текущий URL-адрес удаляется из стека, и браузер получает доступ к предыдущему.
codechick

СodeСhick.io - простой и эффективный способ изучения программирования.

2024 ©