
- •1. Введение
- •2. Элементы языка
- •2.1. Первые программы
- •2.2. Алфавит языка
- •2.3. Комментарии
- •2.4. Типы данных
- •2.5. Целые типы данных
- •2.6. Плавающие типы данных
- •2.7. Константы-строки, или литералы
- •2.8. Директива препроцессора define
- •2.9. Описания
- •2.10. Модификатор const
- •3. Выражения
- •3.1. Операция и выражение присваивания
- •3.2. Арифметические операции
- •3.3. Операции отношения
- •3.4. Логические операции
- •3.5. Побитовые операции
- •3.6. Сдвиги
- •?????3.8. Тернарная или условная операция
- •3.9. Операция следования
- •3.10. Приоритеты операций и порядок вычисления
- •4.6. Оператор выбора switch
- •4.7. Оператор цикла while
- •4.8. Цикл с постусловием do-while
- •4.9. Оператор for
- •4.10. Оператор безусловного перехода
- •4.11. Оператор break
- •4.12. Оператор continue
- •4.13. Оператор return
- •5. Указатели
- •5.1. Определение указателей
- •5.2. Указатели и массивы
- •5.3. Адресная арифметика
- •5.4. Символьные массивы и строки
- •5.5. Многомерные массивы
- •5.6. Указатели и многомерные массивы
- •6. Операция sizeof
- •7. Операции для работы с динамической памятью
- •7.1. Операция выделения памяти new
- •7.2. Операция освобождения памяти delete
- •8. Функции
- •8.1. Определение и вызов функции
- •8.2. Функции. Передача аргументов
- •8.3. Передача многомерных массивов
- •8.4. Указатели на функции
- •8.5. Ссылки
- •8.6. Ссылки в качестве параметров функций
- •8.7. Аргументы по умолчанию
- •8.8. Переопределение функций
- •8.9. Шаблоны функций
- •9. Объявления и определения
- •10. Область существования имени
- •11. Область видимости
- •Здесь будет напечатано
- •12. Классы памяти
- •13. Объявления объектов и типов
- •14. Имена типов
- •15. Синоним имени типа
- •16. Правила преобразования стандартных типов
- •16.1. Явные преобразования
- •16.2. Неявные преобразования стандартных базовых типов
- •16.3. Преобразование производных стандартных типов
- •17. Перечисления
- •18. Классы
- •18.1. Объявление классов
- •18.2. Конструкторы
- •18.3. Деструкторы
- •18.4. Статические члены класса
- •18.5. Указатель this
- •18.6. Статические функции-члены
- •18.7. Указатели на члены класса
- •18.8. Инициализация данных–членов класса
- •18.9. Конструктор копирования и операция присваивания
- •18.10. Дружественные функции
- •18.11. Конструктор и операция new
- •18.12. Вызов деструктора
- •19. Производные классы
- •19.1. Построение производного класса
- •19.2. Защищенные члены класса
- •19.3. Управление уровнем доступа к членам класса
- •19.4. Последовательность вызова конструктора и деструктора при построении производного класса на основе одного базового
- •19.5. Преобразования типов
- •20. Полиморфизм
- •20.1. Раннее и позднее связывание
- •20.2. Виртуальные функции
- •20.3. Абстрактные классы
- •21. Переопределение стандартных операций
- •21.1. Основные определения и свойства
- •21.2. Операции new и delete при работе с абстрактными типами
- •21.3. Использование new при создании динамического объекта абстрактного типа
- •21.4. Операция delete
- •21.5. Преобразование типов
- •22. Некоторые особенности переопределенных операций
- •22.2. Операция [ ]
- •23. Классы и шаблоны
- •24. Списки
- •24.1. Операции над односвязными списками
- •24.2. Двунаправленные и кольцевые списки
- •24.3. Операции над кольцевыми списками
- •25. Стеки
- •25.1. Реализация стека через массив
- •25.2. Реализация стека через динамическую цепочку звеньев
- •26. Двоичные деревья
- •26.1. Определение и построение
- •26.2.Таблицы
- •27. Список литературы
25.2. Реализация стека через динамическую цепочку звеньев
Пусть значением указателя, представляющего стек в целом, является адрес вершины стека. Как и в случае односвязного списка, каждое звено будет содержать указатель на следующей элемент, причем «дно» стека (т.е. элемент, занесенный в стек раньше всех) содержит указатель NULL.
// Файл stack.cpp
typedef char ETYPE;
struct elem {
ETYPE data;
elem* next;
elem (ETYPE d, elem* n){ data = d; next = n; }
};
class stack {
elem*h; // Адрес вершины стека.
public:
stack () {h = NULL;} // Создание пустого стека.
stack (ETYPE a [ ], int len){ // Инициализация стека массивом.
h = NULL;
for (int i = 0; i< len; i++) h = new elem (a[i], h);
}
stack (stack & a){ // Инициализация стека другим стеком.
elem *p,*q;
p = a.h; q = NULL;
while (p) { q = new elem (p->data, q);
if (q->next = = NULL) h = q;
else q->next->next = q;
p = p->next;
}
q->next = NULL;
}
~stack () {reset ();}
void push (ETYPE c) { h = new elem (c, h); } // Поместить в стек.
ETYPE pop () { elem *q = h; ETYPE a = h->data; // Извлечь из стека.
h = h->next; delete q;
return a;
}
ETYPE pop_show () {return h->data;} // Показать вершину.
void reset () { while (h ){ elem *q = h; h = h->next; delete q; }
}
int empty () { return h ? 0:1;}
};
// Конец файла stack.cpp
Приведем задачу, в решении которой удобно использовать стек.
В файле задана строка литер. Требуется проверить баланс скобок в этой строке.
Баланс соблюдается, если выполнено каждое из следующих условий:
Для каждой открывающей скобки справа от нее есть соответствующая закрывающая скобка. Наоборот, для каждой закрывающей скобки слева от нее есть соответствующая открывающая скобка.
Соответствующие пары скобок разных типов правильно вложены друг в друга.
Так в строке
{[(a*b)+(n-4)]/[7-sin(x)]+exp(d)}*s
баланс скобок соблюдается, а в строке
[{a+b[i]((x-sin(x))]d)) – нет.
В качестве результата необходимо вывести сообщение о соблюдении баланса, а также начало строки до первого по порядку нарушения баланса скобок.
Для решения задачи сформируем сначала пустой стек. Затем будем последовательно просматривать литеры строки. Если очередной символ окажется открывающей скобкой, выберем последнюю из занесенных в стек открывающих скобок и сравним эти скобки на соответствие друг другу. Если соответствие есть, то эффект должен быть такой же, как если бы этой пары скобок в строке вообще не было. Если эти скобки не соответствуют друг другу, то выполнено второе условие соблюдения баланса скобок. Если же в момент выбора из строки очередной закрывающей скобки стек оказался пуст или по завершении просмотра стек оказался не пуст, то не выполнено первое условие соблюдения баланса скобок.
Обозначим через s – стек, sym – обрабатываемый символ, а через b-– целую переменную, фиксирующую факт соответствия закрывающей скобки из строки с открывающей скобкой из вершины стека. Для проверки на соответствие закрывающей скобки, являющейся значением переменной sym, и открывающей скобки в вершине стека опишем специальную функцию accord(), которая возвращает целое значение и удаляет открывающую скобку из стека.
# include <fstream.h>
# include <stdlib.h>
# include “stack.cpp“
int accord (stack & s, char sym){
char r = s.pop ( );
switch (sym) {
case ‘)’ : return r = = ‘(‘;
case ‘]’ : return r = = ‘[‘;
case ‘}’ : return r = = ‘{‘;
default : break;
}
}
void main ( ) {
ifstream file ( “a.dat“ );
if ( !file ){ cout << “Ошибка при открытии файла a.dat!\n“; exit(1); }
stack s;
char sym; int i, n, b = 1;
while ( file.peek () != EOF && b){
file >> sym; cout <<sym;
switch (sym){
case ‘(’ : case ‘[’ : case ‘{’ : s.push(sym); break;
case ‘)’ : case ‘]’ : case ‘}’ :
if ( s.empty () || !accord (s, sym)) b = 0; break;
}
}
if (!b || !s.empty ()) cout <<”\nБаланса скобок нет!\n”;
else cout <<”\nСкобки сбалансированы\n”;
}