Структуры данных: общее понятие, реализация. Простейшие структуры данных: очередь, стек. Использование стека и обратная польская запись
Реализация стека на языке Си
Реализуем стек вещественных чисел. Ниже мы используем эту реализацию как составную часть проекта Стековый калькулятор (см. раздел 4.4.2).
Реализация включает два файла: "streal.h", в котором описывается интерфейс исполнителя "Стек", и "streal.cpp", реализующий функции работы со стеком. Слово real обозначает вещественное число.
Используется первый вариант реализации стека на базе массива, описанный в предыдущем разделе: стек растет в сторону увеличения индексов массива. Пространство под массив элементов стека захватывается в динамической памяти в момент инициализации стека. Функции инициализации st_init передается размер массива, т.е. максимально возможное число элементов в стеке. Для завершения работы стека нужно вызвать функцию st_terminate, которая освобождает захваченную в st_init память. Ниже приведено содержимое файла "streal.h", описывающего интерфейс стека.
// Файл "streal.h" // Стек вещественных чисел, интерфейс // #ifndef ST_REAL_H #define ST_REAL_H // Прототипы функций, реализующих предписания стека: void st_init(int maxSize); // Начать работу (вх: цел // макс. размер стека) void st_terminate(); // Закончить работу void st_push(double x); // Добавить эл-т (вх: вещ x) double st_pop(); // Взять элемент: вещ double st_top(); // Вершина стека: вещ int st_size(); // Текущий размер стека: цел bool st_empty(); // Стек пуст? : лог int st_maxSize(); // Макс. размер стека: цел bool st_freeSpace(); // Есть свободное место? : лог void st_clear(); // Удалить все элементы double st_elementAt(int i); // Элемент стека на // глубине (вх: i): вещ #endif // Конец файла "streal.h"
Отметим, что директивы условной трансляции
#ifndef ST_REAL_H #define ST_REAL_H . . . #endif
используются для предотвращения повторного включения h-файла: при первом включении файла определяется переменная препроцессора ST_REAL_H, а директива " #ifndef ST_REAL_H " подключает текст, только если эта переменная не определена. Такой трюк используется практически во всех h-файлах. Нужен он потому, что одни h-файлы могут подключать другие, и без этого механизма избежать повторного включения одного и того же файла трудно.
Файл "streal.cpp" описывает общие статические переменные, над которыми работают функции, соответствующие предписаниям стека, и реализует эти функции.
// Файл "streal.cpp" // Стек вещественных чисел, реализация // #include <stdlib.h> #include <assert.h> #include "streal.h" // Подключить описания функций стека // Общие переменные для функций, реализующих // предписания стека: static double *elements = 0; // Указатель на массив эл-тов // стека в дин. памяти static int max_size = 0; // Размер массива static int sp = (-1); // Индекс вершины стека // Предписания стека: void st_init(int maxSize) { // Начать работу (вх: // макс. размер стека) assert(elements == 0); max_size = maxSize; elements = (double *) malloc( max_size * sizeof(double) ); sp = (-1); } void st_terminate() { // Закончить работу if (elements != 0) { free(elements); } } void st_push(double x) { // Добавить эл-т (вх: вещ x) assert( // утв: elements != 0 && // стек начал работу и sp < max_size-1 // есть своб. место ); ++sp; elements[sp] = x; } double st_pop() { // Взять элемент: вещ assert(sp >= 0); // утв: стек не пуст --sp; // элемент удаляется из стека return elements[sp + 1]; } double st_top() { // Вершина стека: вещ assert(sp >= 0); // утв: стек не пуст return elements[sp]; } int st_size() { // Текущий размер стека: цел return (sp + 1); } bool st_empty() { // Стек пуст? : лог return (sp < 0); } int st_maxSize() { // Макс. размер стека: цел return max_size; } bool st_freeSpace() { // Есть своб. место? : лог return (sp < max_size - 1); } void st_clear() { // Удалить все элементы sp = (-1); } double st_elementAt(int i) { // Элемент стека на // глубине (вх: i): вещ assert( // утв: elements != 0 && // стек начал работу и 0 <= i && i < st_size() // 0 <= i < размер стека ); return elements[sp - i]; } // Конец файла "streal.cpp"