Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Пособие часть1.doc
Скачиваний:
22
Добавлен:
01.03.2025
Размер:
6.94 Mб
Скачать

2.2.2. Ссылочная реализация стека в динамической памяти

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

Рисунок 2.2. поясняет идею cсылочной реализации стека. Отдельный указатель содержит адрес самого последнего элемента, который будет вершиной стека ( top).

Рис.2.2. Ссылочная реализация стека с помощью списка в динамической памяти

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

template <class T> // шаблонный тип элементов стека

struct item //структура каждого элемента стека

{ T data; // данные

item<T> *prev; // указатель на предыдущий элемент

};

Как видно из рисунка 2.2, для реализации базовых функций стека требуется только один указатель на вершину (top). В остальном определение структуры выполняется аналогично определению предыдущей реализации на основе массива, небольшие отличия в синтаксисе связаны с использованием шаблонов.

template <class T> struct stack //структура стека

{ item<T> *top;

// базовые функции для работы со стеком

stack() {top=NULL;} //конструктор, создание пустого стека

void push (T x); // поместить значение x в стек

void pop();// извлечь элемент с вершины стека

T gettop();// получить вершину стека

bool isnull() {return top==NULL;} // проверка на пустоту

void makenull(); // дополнительная функция очистки стека

};

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

Для вставки необходимо:

  • захватить память под новый элемент, заполнить данными содержательную часть;

  • указующей части присвоить значение указателя на вершину;

  • присвоить указателю на вершину адрес нового элемента (он теперь будет вершиной).

template <class T> void stack<T>::push(T x)

{ item<T> *p=new item<T>;

p->data=x; p->prev=top; // добавили элемент

top=p; // изменили указатель на вершину top

}

При извлечении элемента необходимо:

  • изменить указатель на вершину стека (теперь вершиной будет предпослений элемент);

  • освободить память, которую занимал последний элемент;

template <class T> void stack<T>::pop ()

{ if (isnull()) {cerr<< "Стек пуст \n"; exit(1);};

item<T> *p=top; top=top->prev; // изменили указатель top

delete p; // удалили элемент

}

Возвратить последний элемент из буфера не представляет труда:

template <class T> T stack<T>::gettop()

{ if (isnull()) {cerr<< "Стек пуст \n"; exit(1);};

return top->data;

}

Дополнительная функция очистки стека реализуется через базовые:

template <class T> void stack<T>::makenull()

{ while (!isnull()) pop(); // удаляем элементы по очереди

}

При использовании данной реализации описание конкретного стека с элементами, например, типа char, будет иметь вид

stack<char> имя;

В прикладных программах-клиентах, использующих стеки, можно пользоваться любой реализацией, при этом будем иметь одинаковую функциональность. В дальнейшем будем считать, что шаблон стека находится в файлах stack.h (интерфейс) и stack.cpp (реализация), который можно подключать к различным программам, использующим стек как элементарную структуру данных.