IVМеждународная научно-практическая конференция УДК 004.021
Романова Полина Сергеевна Romanova Polina Sergeevna
Студент Student
Никульшина Татьяна Александровна Nikulshina Tatiana Alexandrovna
Старший преподаватель Senior lecturer Погорелов Дмитрий Александрович Pogorelov Dmitriy Alexandrovich
Ассистент Assistant
Московский государственный технический университет имени Н.Э. Баумана Bauman Moscow State Technical University
ПРОВЕРКА ПРАВИЛЬНОСТИ РАССТАНОВКИ СКОБОК ТРЁХ ТИПОВ
(КРУГЛЫХ, КВАДРАТНЫХ И ФИГУРНЫХ) В ВЫРАЖЕНИИ,
НА ОСНОВЕ СТЕКА
CHECKING THE CORRECT PLACEMENT OF THREE TYPES OF BRACKETS (ROUND, SQUARE AND CURLY) IN A STACK-BASED
EXPRESSION
Аннотация: Рассмотрены операции работы со стеком, представленного в виде массиве и в виде односвязного линейного списка, оценены преимущества и недостатки каждой реализации при проверке правильности расстановки скобок трёх типов.
Abstract: The operations of working with a stack represented as an array and as a simply connected linear list are considered, and the advantages and disadvantages of each implementation are evaluated when checking the correctness of the placement of three types of brackets.
Ключевые слова: стек, массив, односвязный список, расстановка скобок.
Keywords: stack, array, singly linked list, bracket arrangement.
Стек - это последовательный список с переменной длиной, в котором включение и исключение элементов происходит только с одной стороны - с его вершины. Стек функционирует по принципу: последним пришел - первым ушел, Last In - First Out (LIFO) [1].
«Инновационные аспекты развития науки и техники» Программная реализация стека возможна на основе различных структур
данных, например, с использованием статических или динамических
одномерных массивов (векторов) и линейных списков.
При работе со стеком доступен только его верхний элемент, который
адресуется специальным указателем стека PS (Pointer Stack). Причем
классическая реализация стека предполагает, что просмотреть содержимое стека
без извлечения (удаления) его элементов невозможно.
При работе со стеком необходимо отслеживать возникновение таких
аварийных ситуаций, как попытки исключения элемента из пустого стека и
переполнения стека. При реализации стека в виде вектора переполнение
возникает вследствие ограниченности объема памяти, выделяемой под
размещение массива. Однако даже если стек реализован на основе
динамического списка, его размер также не безграничен, он ограничен объемом
доступной программе оперативной памяти. Для отработки указанных аварийных
ситуаций в программе должны быть предусмотрены дополнительные проверки
на пустоту и переполнение стека и выдача соответствующих сообщений [2].
При написании выражений, использующих скобки, важно на этапе
фронтенда сразу определить и уведомить пользователя о том, что
последовательность имеет какие-то некорректности во вводе:
не хватает скобок какого-то вида;
слишком много скобок какого-то вида.
Таким образом, рассмотрим реализацию решения данной задачи на основе стека, при этом реализация стека будет представлена в виде массива и в виде односвязного линейного списка, чтобы можно было оценить преимущества и недостатки каждой реализации. Структура проекта
Для начала разберёмся со структурой, которая будет представлять узел списка или самого массива (рис. 1).
IVМеждународная научно-практическая конференция Структура узла для списка:
struct node *previou3_eT;
Реализация массива-стека:
Рис. 1. Структуры данных
Очевидно, так как необходима реализация в виде стека, то необходимо хранить указатель на вершину стека в основном коде.
Рассмотрим, какие функции будут необходимы при взаимодействии со стеком-массивом (рис. 2).
int push arr (char curr, char +p end, value) '>
Рис. 2. Взаимодействие со стеком-массивом
Рассмотрим, какие функции будут необходимы при взаимодействии со стеком-списком:
struct node* push list(struct node *last el, char value, int fl an);
Рис. 3. Взаимодействие со стеком-списком
Также в реализации следует предусмотреть функцию для анализа времени выполнения и анализа расстановки скобок. Реализация описанных функций
«Инновационные аспекты развития науки и техники» Рассмотрим непосредственные реализации всех описанных в предыдущем
пункте функций:
- функции работы со стеком-массивом (рис. 4);
- функции работы со стеком-списком (рис. 5);
- функция анализа времени выполнения (рис. 6);
- функция анализа расстановки скобок (рис. 7).
4finclude <stdio.h> #include "array_staclc.h"
int push_arr(char **p_currJ char *p_endj char value)
5 {
if (*p_curr >= p_end) {
printf( "Overflow of array\n")j
return -1;
>
(*p_curr)-t~t-; **p_curr = value; return
-5 }
int pop_ar-(char **p_curri char *p_beg)
-3 {
if (*p_curr -i p_beg) // Array is empty return -1;
(*p_curr)--; return
}
29 Id
void print_arr(char *p_beg, char *p_curr)
if (P_beg > p_curr)
printf ("Array is empty .\n")_;
for(;p_beg <= p_curr; p_beg+-i-) printf("Sc "j *p_beg)j
Рис. 4. Реализация функций работы со стеком-массивом
»include <stdio.h> »include <stdlib.h> 3 »include "list_stack:.h"
static void *:s:free_area; static int n =
3 void init_free_area()
9 {
free_area = calloc(Mj ¿izeof(void*)};
:: >
13 U returns address of new last element
struct node* push_list(struct node *last_el, char valued
15 {
struct node *tmp = malloc(sizeo-(struct node});
tmp->value = value;
tmp->previous_el = last_el;
return tmp;
21 >
23 U returns address of new last element
struct node* pop_list(struct node *last_elj int fl_an)
25 {
if (last_el == NULL) {
printf("List is empty.\n"); return NULL;
}
struct node *tmp = last_el->previous_el;
if (fl_an)
free_area[n++] = (void *) last_el;
free(la5t_el);
return tmp;
49 >
void print_list(struct node *last_el) {
if (lsst el == HULL)
printff'List is empty.\n"};
forf; last_el != NULL; last_el = last_el->previous_el) printf("!Sc (Snp)\n", last_el->value, last_el};
printf("\nFree area:\n");
for(int j = 9; j < n; j++)
printf("№p "j free_area[j]);
putsC"");
54 >
Рис. 5. Реализация функций работы со стеком-списком
«Инновационные аспекты развития науки и техники»
void analyse (int 11} {
printf("--------Analyse for %d size--------\n", N);
unsigned long long duration; unsigned long long tlj t2;
char char
struct node *last_element - NULL;
printf("Array stack size: %d\n"j sizeof(arrstack) + sizeof(p_curr));
printf("List stack size: Kd to 3id\n"j sizeof (last_e lenient), sizeof(last_element) + sizeof (struct node}*«}; printf("PUSH operation:\n">; tl = tickf);
forfint 1=0; i <: Pi; i++}
pjsli_arr[6p_currj arrstack + II - 1, '1'};
tl = tickf);
duration - (unsigned long long} (t2-tl); printf("YtArray stack: %l5llu\n"j duration);
tl = tickO;
for(int i = 8; i < H; i++}
last_element - push_listClast_elementj 'l"J;
tl = tickO;
duration - (unsigned long long) ft2-tl);
printf("VtList stack : S1511u\n"j duration);
printf ("POP operation An"]; tl = tick();
forfint i = a; i < h; i++}
pop_arr[ap_currj arrstack^;
tl = tick();
duration - (unsigned long long) (ta-tl); printf(" YtArray stack: %l5llu\n"j duration);
tl = tickf);
for(int i = 8; i < N; i++}
last_element - poF_list(last_elementj 0);
tl = tick();
duration = (unsigned long long) (t2-tl); printf("VtList stack : XlSlluWVr", duration);
Рис. 6. Функция анализа времени выполнения
arrstack[N];
curr - arrstack - l;
int checlc_parenthesesQ (
struct node *last_el = NULL; char str[RAX_LOi];
prinrtfCMax len of string is M\n", h»;_len-i); prirtf["Input expression:\rI"); for (int i = 0; i < RW£_LBI-3; i++;
prinrtff"-";; prirtfC"|\r"!;
scarfC"«s"J str); str [HftX_LE pi—i] = 1 \e1
for {char *ptr = str; *ptr; ptr++) (
if (*ptr == ■[■ | "ptr == ■[■ || <ptr == ■{■) last_el = push_listClast_elj *ptrj;
else if {«ptr == ')■ | -ptr == ']■ || "ptr == ■)■) {
if [!last_el) return -1;
if {{*ptr == ■)■ as last_el->value == ■[■) || [«ptr == 1]1 (U last_el-lvalue == ■[■) || [«ptr == ■>■ as last_el-lvalue == ■{■)) last_el = pop_list(last_elj 0);
else
return -1;
>
if (last_el) return -1;
return 0;
Рис.7. Функция анализа расстановки скобок
Анализ эффективности (по памяти и времени)
Используя реализованные функции, проведём анализ эффективности по памяти и времени рассмотренных вариантов реализации (рис. 8).
8
--------Analyse for 1300 size-------
Array stack size: 1008 List stack size: 8 to 16008 PUSH operation:
Array stack: 7292
List stack : 167346
POP operation:
Array stack: 5124
List stack : 53800
--------Analyse for 10000 size------
Array stack size: 10008 List stack size: 8 to 160308 PUSH operation:
Array stack: 70472
List stack : 941284
POP operation:
Array stack: 50378
List stack : 749160
Рис. 8. Анализ эффективности (по памяти и времени)
«Инновационные аспекты развития науки и техники»
Как видим, работа с массивом происходит в 10 раз быстрее, чем со
списком. При этом, в наихудшем случае список будет занимать в 16 раз больше памяти, чем массив, в наилучшем - 8 байт (место под нулевой указатель).
Таким образом можно сделать вывод, что для хранения стека небольшого объёма целесообразнее использовать список, так как это даёт заметный выигрыш по времени выполнения. При неопределённом количестве элементов, или когда максимальное количество элементов гораздо больше среднего, целесообразнее использовать массив.
Библиографический список:
1. Вирт Н. Алгоритмы и структуры данных: Пер. с англ.- СПб.: Невский диалект, 2001. С. 69-71, 205-235
2. Ахо А., Хопкрофт Д., Ульман Д. Структуры данных и алгоритмы.: Пер. с англ. М.: Издат. дом «Вильямс», 2000. С. 58-76