Міністерство освіти І науки України
національний університет “Львівська політехніка”
Кафедра ЕОМ
Структура даних СТЕК
Методичні вказівки
До лабораторної роботи № 3 з дисципліни
" Програмування. Частина III.
Структури даних та алгоритми "
для студентів напряму
6.050102 “Комп’ютерна інженерія”
Затверджено
на засідання кафедри
“Електронні обчислювальні машини”.
Протокол № __ від ________ 2012
р. р.
Львів – 2012
1. МЕТА РОБОТИ
Вивчення фундаментальної абстрактної структури даних стек. Набуття практичних навичок побудови стека, дослідження динаміки його вмісту та використання стеків для розв'язання прикладних задач.
2. Теоретичні відомості
Стек - динамічна структура даних, що представляє собою впорядкований набір елементів, у якій додавання нових елементів і видалення існуючих відбувається з одного кінця, який називається вершиною стека. Згідно визначення, елементи вилучаються зі стека в порядку, зворотному їхньому додаванню в цю структуру, тобто діє принцип LIFO (Last In, Fist Out – останнім прийшов, першим вийшов).
Найбільш наочним прикладом організації стека служить дитяча пірамідка, в якій додавання й зняття кілець здійснюється саме відповідно до визначення стека. Можна уявити також стопку тарілок. Нижня тарілка із цієї стопки буде використана останньою, а верхня тарілка, яка була покладена в стопку останньою, буде використана першою. Подібне відбувається й в стеку.
Стеки широко використовуються як для розв’язання прикладних задач, так і в системному програмному забезпеченні, включаючи компілятори і інтерпретатори.
Історично склалося так, що дві основні операції для стека - помістити в стек і вилучити зі стека - одержали назву відповідно "заштовхнути" і "виштовхнути". Тому для реалізації стека необхідно створити дві функції: "push" (заштовхнути), що поміщає елемент у вершину стека, і "pop" (виштовхнути), що вилучає з вершини стека один елемент. Необхідно також передбачити певну область у пам'яті, де фактично буде зберігатися стек. Для цього можна використати масив або можна виділити область пам'яті, використовуючи засоби динамічного розподілу пам'яті.
Приклад 1:
Нехай задана послідовність: 7 , 5 , 9 , 2 . Непарні числа цієї послідовності додаються у стек, а кожне парне число вилучає зі стеку один елемент.
Нижче показана динаміка вмісту стека під час обробки заданої послідовності:
Порожній стек |
Елементи вхідної послідовності |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7 |
5 |
9 |
2 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Функції : |
push(7); |
push(5); |
push(9); |
top(); pop(); |
Оскільки стек - це важлива абстракція даних, у стандартній бібліотеці С++ передбачений клас stack, для використання якого потрібно включити заголовочний файл:
#include <stack>
Повний набір стандартних операцій роботи зі стеком показаний у таблиці:
Операція |
Дія |
empty() |
Повертає true, якщо стек порожній, і false у противному випадку |
sіze() |
Повертає кількість елементів у стеку |
pop() |
Видаляє елемент із вершини стека, але не повертає його значення |
top() |
Повертає значення елемента з вершини стека, але не видаляє його |
push(іtem) |
Додає новий елемент у стек |
У наведеній програмі показані приклади використання цих операцій:
#include <stack>
#include <iostream>
int main()
{
const int ia_size = 10;
int ia[ia_size]={0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
// заповнення стеку
int ix = 0;
stack< int > intStack;
for ( ; ix < ia_size; ++ix )
intStack.push( ia[ ix ] );
int error_cnt = 0;
if ( intStack.size() != ia_size ) {
cerr << "Помилка! Неправильний розмір IntStack: " // cerr - вихідний потік
<< intStack.size() // повідомлень про помилки
<< "\t очікується: " << ia_size << endl,
++error_cnt;
}
int value;
while ( intStack.empty() == false )
{
// зчитування елемента з вершини стека
value = intStack.top();
if ( value != --ix ) {
cerr << " Помилка! очікується " << ix
<< " отримано " << value << endl;
++error_cnt;
}
// вилучення елемента
intStack.pop();
}
cout << "В результаті запуску програми отримано "
<< error_cnt << " помилок" << endl;
}
До двох стеків одного типу можна застосовувати операції порівняння: рівність, нерівність, менше, більше, менше або дорівнює, більше або дорівнює, якщо вони визначені над елементами стека. Елементи порівнюються попарно. Перша пара неспівпадаючих елементів визначає результат операції порівняння в цілому.
Розглянемо реалізацію стека на базі масиву з фіксованим розміром. В наведеному далі лістінгу показано заголовочний файл для шаблонного класу stack, аналогічний класу stack зі стандартної бібліотеки шаблонів STL.
// ФАЙЛ: stack1.h
// ЗАБЕЗПЕЧУВАНИЙ ШАБЛОННИЙ КЛАС: stack<Item>
//
// ШАБЛОННИЙ ПАРАМЕТР, ОПЕРАТОРИ ПЕРЕІМЕНОВАННЯ ТИПІВ
// ТА КОНСТАНТНІ ЧЛЕНИ класу stack<Item>
// Шаблонний параметр Item уявляє собою тип елементів,
// що зберігаються у стеку. Він визначається також як
// stack<Item>::value_type
// і може бути довільним вбудованим типом в мові С++ (int, char і т.д.),
// а також класом, в якому визначений конструктор по замовчуванню,
// конструктор копіювання і оператор присвоєння. Визначення типу
// stack<Item>::size_type відноситься до довільної змінної, в якій зберігається
// кількість елементів стека. В цій реалізації константа
// stack<Item>:: CAPACITY означає максимальну кількість елементів довільного
// стека (як тільки ця кількість буде досягнута, додавання
// елементів у стек припиняється).
//
// КОНСТРУКТОР ШАБЛОННОГО КЛАСУ stack<Item>:
// stack()
// Післяумова: стек ініціалізується порожнім.
//
// МОДИФІКУЮЧІ ФУНКЦІЇ-ЧЛЕНИ шаблонного класу stack<Item>:
// void push(const Item& entry)
// Передумова: size( ) < CAPACITY.
// Післяумова: в стек занесена нова копія елемента.
//
// void pop( )
// Передумова: size( ) > 0.
// Післяумова: вилучена вершина стека.
//
// КОНСТАНТНІ ФУНКЦІЇ-ЧЛЕНИ шаблонного класу stack<Item>:
// Item top( ) const
// Передумова: size( ) > 0.
// Післяумова: повертається вершина стека, однак стек при цьому
// не змінюється. Цим цей клас дещо відрізняється від стека,
// що описаний в стандартній бібліотеці шаблонів STL ( в якому
// функція top повертає посилання на елемент, що знаходиться у
// вершині стека).
//
// size_type size( ) const
// Післяумова: повертає загальну кількість елементів у стеку.
//
// bool empty( ) const
// Післяумова: повертає значення true, якщо стек порожній,
// и значення false, якщо це не так.
//
// СЕМАНТИКА ЗНАЧЕНЬ для шаблонного класу stack<Item>.
// До об'єктів класу stack<Item> можна застосувати операцію
// присвоєння і конструктор копіювання.
#ifndef MAIN_SAVITCH_STACK1_H
#define MAIN_SAVITCH_STACK1_H
#include <cstdlib> // Надає тип size_t.
namespace main_savitch_7A
{
template <class Item>
class stack
{
public:
// ОПЕРАТОРИ ПЕРЕТВОРЕННЯ ТИПІВ ТА КОНСТАНТНІ ЧЛЕНИ
typedef std::size_t size_type;
typedef Item value_type;
static const size_type CAPACITY = 30;
// КОНСТРУКТОР
stack( ) { used = 0; }
// МОДИФІКУЮЧІ ФУНКЦІЇ-ЧЛЕНИ
void push(const Item& entry);
void pop( );
// КОНСТАНТНІ ФУНКЦІЇ-ЧЛЕНИ
bool empty( ) const { return (used == 0); }
size_type size( ) const { return used; }
Item top( ) const;
private:
Item data[CAPACITY]; // Частково заповнений масив.
size_type used;
};
}
#include "stack1.template" // Директива включення реалізації.
#endif
Файл реалізації класу stack показаний в наступному лістінгу:
// ФАЙЛ: stack1.template
// РЕАЛІЗОВАНИЙ ШАБЛОННИЙ КЛАС stack<Item>:
// Цей файл входить до складу заголовочного і окремо не компілюється.
// Інваріант класу stack:
// 1. Кількість елементів у стеку зберігається у змінній-члені used.
// 2. Елементи стека знаходяться у частково заповненому масиві data. На дні стеку // знаходиться елемент data[0], далі - data[1] і так далі аж до вершини стека, // у якій розташований елемент data[used-1].
#include <cassert> // Надає макрос assert.
namespace main_savitch_7A
{
template <class Item>
const typename stack<Item>::size_type stack<Item>::CAPACITY;
template <class Item>
void stack<Item>::push(const Item& entry)
// ВИКОРИСТОВУВАНА БІБЛІОТЕКА: cassert
{
assert(size( ) < CAPACITY);
data[used] = entry;
++used;
}
template <class Item>
void stack<Item>::pop( )
// ВИКОРИСТОВУВАНА БІБЛІОТЕКА: cassert
{
assert(!empty( ));
--used;
}
template <class Item>
Item stack<Item>::top( ) const
// ВИКОРИСТОВУВАНА БІБЛІОТЕКА: cassert
{
assert(!empty( ));
return data[used-1];
}
}