Стек

Последнее обновление: 02.09.2016

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

Каждый элемент в стеке, как и в односвязном списке, будет представлен классом Node:

public class Node<T>
{
    public Node(T data)
    {
        Data = data;
    }
    public T Data { get; set; }
    public Node<T> Next { get; set; }
}

На основе класса Node мы можем реализовать структуру стек:

using System;
using System.Collections.Generic;
using System.Collections;

namespace SimpleAlgorithmsApp
{
    public class NodeStack<T> : IEnumerable<T>
    {
        Node<T> head;
        int count;

        public bool IsEmpty
        {
            get { return count == 0; }
        }
        public int Count
        {
            get { return count; }
        }

        public void Push(T item)
        {
            // увеличиваем стек
            Node<T> node = new Node<T>(item);
            node.Next = head; // переустанавливаем верхушку стека на новый элемент
            head = node;
            count++;
        }
        public T Pop()
        {
            // если стек пуст, выбрасываем исключение
            if (IsEmpty)
                throw new InvalidOperationException("Стек пуст");
            Node<T> temp = head;
            head = head.Next; // переустанавливаем верхушку стека на следующий элемент
            count--;
            return temp.Data;
        }
        public T Peek()
        {
            if (IsEmpty)
                throw new InvalidOperationException("Стек пуст");
            return head.Data;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable)this).GetEnumerator();
        }

        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            Node<T> current = head;
            while (current != null)
            {
                yield return current.Data;
                current = current.Next;
            }
        }
    }
}

В отличие от предыдущей реализации стека, построенной на массивах, здесь мы уже уходим от ограничения, которые накладывали массивы - нам не надо пересоздавать массив при добавление в него или удалении из него данных. Нам достаточно переустановить ссылку на элемент head, который является верхушкой стека. При этом алгоритмическая сложность обоих методов Push и Pop составляет O(1).

Таким образом, мы получили относительно простое и достаточно эффективное решение.

Применение стека:

NodeStack<string> stack = new NodeStack<string>();
stack.Push("Tom");
stack.Push("Alice");
stack.Push("Bob");
stack.Push("Kate");

foreach (var item in stack)
{
    Console.WriteLine(item);
}
Console.WriteLine();
string header = stack.Peek();
Console.WriteLine($"Верхушка стека: {header}");
Console.WriteLine();

header = stack.Pop();
foreach (var item in stack)
{
    Console.WriteLine(item);
}

Консольный вывод:

Kate
Bob
Alice
Tom

Верхушка стека: Kate

Bob
Alice
Tom
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850