Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
uchebno-metodicheskoe_posobie_SiAOD_1chast / учебно-методическое пособие СиАОД 1часть.doc
Скачиваний:
94
Добавлен:
20.03.2015
Размер:
1 Mб
Скачать

1.4. Реализация стека на основе статического массива

Пример 1:

В качестве задачи поставим разработку стека для хранения вещественных чисел, например, из 20-ти вещественных чисел.

#include <iostream.h>

struct Stack

{ int top;

double v[20];};

void push( Stack& s, double val ) // функция добавления элемента

{

s.v[s.top] = val;

s.top++;

}

double pop( Stack& s ) // функция удаления элемента

{

return s.v[--(s.top)];

}

void init( Stack& s ) //функция инициализации стека

{

s.top = 0;

}

bool full( Stack& s ) //функция проверки переполнения стека

{

return s.top >= 20;

}

void main()

{

Stack s;

init( s ); // Инициализация стека

push( s, 2.31); // Помещение в стек первого элемента

push( s, 1.19 ); // Помещение в стек второго элемента

cout << pop( s ) << '\n'; // Извлечение верхнего элемента

// и вывод его на экран

push( s, 6.7 ); // Помещение в стек элемента

push( s, pop(s)+pop(s) ); // Замена двух верхних элементов

// стека их суммой

}

Рис. 2.Стек на основе массива с фиксацией верхушки стека

Стек приведенный в примере реализован на базе статического массива, один из элементов которого играет роль верхушки стека. Индекс этого элемента хранится в компоненте top. (рис. 2).

Серым цветом обозначены помещенные в стек элементы.

Простейшему варианту реализации стека (в виде структуры "Stack") присущи ряд недостатков, которые можно разбить на две группы:

1) Малая гибкость применения

  • У стека ограниченный размер (20 элементов).

  • В стеке могут храниться только значения типа double.

  • Имена функций наподобие "full()" и "init()" очень распространены и может возникнуть конфликт этих имен с именами функций из других библиотек.

2) Безопасность использования стека

  • Внутренние переменные стека не защищены от изменений извне. Поэтому стек легко повредить путем изменения значений компонент структуры. Это может привести к сложно обнаружимым ошибкам.

  • Назначение компонент стека тесно связано с особенностями реализации обслуживающих функций ("init()", "push()", "pop()" и др.).

  • В обслуживающих функциях не предусмотрена обработка типичных ошибок: переполнение стека, попытка извлечения элемента из пустого стека, повторная инициализация стека, нет способа проверки состояния стека (поврежден/не поврежден).

  • Присвоение структур (напр., "A=B") приводит к возникновению висячих указателей, т.к. присвоение компонент-массивов означает присвоение указателей, а не копирование отдельных элементов.

1.5. Реализация стека с использованием динамической памяти

Приведен один из вариантов этой структуры:

struct DStack {

double* bottom;

double* top;

int size; // Это максимальный размер стека,

}; // а не количество элементов в нем

Массив для хранения элементов стека должен создаваться динамически на этапе инициализации. Два внутренних указателя стека ссылаются на начало массива ("bottom") и на элемент-верхушку стека ("top"). Устройство стека на базе динамического массива показана на рис. 3.

Рис. 3.Стек с хранением элементов в динамической памяти

Для работы со стеком целесообразно сделать несколько обслуживающих функций:

1) Инициализация стека.

bool DStack_init( DStack& s, int N ); Эта функция динамически создает целочисленный массив размером N элементов и сохраняет его указатель в компонентах структуры "DStack". Если операция инициализации прошла успешно, то функция возвращает "true", а если памяти недостаточно – то "false".

2) Добавление элемента в стек.

bool DStack_push( DStack& s, double val );

Помещает элемент на верх стека. Возвращает "true", если это удалось сделать, или "false", если стек целиком заполнен.

3) Извлечение верхнего элемента.

double DStack_pop( DStack& s );

Возвращает верхний элемент из стека или возвращает 0.0 (или некоторое другое специально оговоренное значение), если стек пуст.

4) Проверка на пустоту.

bool DStack_empty( Dstack& s );

Возврашает "true", если стек пуст, или "false" в противном случае.

5) Удаление стека.

void DStack_free();

Освобождает динамическую память, занятую при создании стека.

По сравнению со стеком из примера 1, в описанном варианте реализации достигается ряд улучшений:

  • Есть возможность создания стеков разного размера.

  • В обслуживающих функциях предусмотрена обработка элементарных ошибок переполнения и обращения к пустому стеку.

  • Имена обслуживающих функций, начинающиеся с "DStack_", менее вероятно обнаружить в других библиотеках.

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