ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 19.01.2025
Просмотров: 277
Скачиваний: 2
Московский Государственный Открытый Университет
Курсовая работа
по дисциплине: «Структуры и алгоритмы обработки данных»
Выполнил:
студент 2 курс
факультет: ИРЭ
специальность: 230105/с
Данилов А.С. 610184
Проверил:
Найденов В.В.
Москва, 2012
Оглавление
1.Задание 3
2.Описание работы программы 5
3.Блок-схема алгоритма 8
4.Листинг программы 30
Файл infix2postfix.c 30
Файл infix2postfix.h 36
Файл unit_tests.c 37
5.Список используемой литературы 41
Задание
Написать программу на языке С для преобразования выражения из инфиксной (привычной) записи в постфиксную (обратную польскую).
Для перевода выражения из инфиксной формы в постфиксную с учетом приоритетов операций и скобок существует простой алгоритм (Дейкстры). Алгоритм работает со стеком, в котором хранятся знаки операций. Сначала стек пуст. На вход алгоритму подается последовательность лексем (числа, скобки или знаки операций), представляющая некоторое арифметическое выражение, записанное в инфиксной форме. Результатом работы алгоритма является эквивалентное выражение в постфиксной форме. Вводятся приоритеты операций: открывающая скобка имеет приоритет 0, знаки '+' и '–' — приоритет 1 и знаки '*' и '/' — приоритет 2.
-
Пока не достигнут конец входной последовательности, читать очередную лексему и выполнять с ней следующие операции:
если прочитан операнд (число), записать его в выходную последовательность;
если прочитана открывающая скобка, положить её в стек;
если прочитана закрывающая скобка, вытолкнуть из стека в выходную последовательность всё до открывающей скобки, при этом сами скобки уничтожаются (удаляются из стека и в ответ не идут);
если прочитан знак операции, вытолкнуть из стека в выходную последовательность все операции с большим либо равным приоритетом, а прочитанную операцию положить в стек.
Если достигнут конец входной последовательности, вытолкнуть всё из стека в выходную последовательность и завершить работу.
Заметим, что порядок операндов в выходной последовательности не отличается от порядка операндов в исходной последовательности. В выходной последовательности отсутствуют скобки.
Пример:
ввод:
(1 + 23 * 4)*(5 - 1)
вывод:
1 23 4 * + 5 1 - *
В качестве операндов допустимы как целочисленные константы, так и имена переменных.
Имя переменной может содержать символы A-Z,a-z,0-9,_, но начинаться с цифры не может. Решение оформить в виде отдельного .c модуля, .h файл приведен ниже. Снабдить модульными тестами (unit-tests).
#ifndef INFIX2POSTFIX_H
#define INFIX2POSTFIX_H
/* типы лексем: константы, операции, имена переменных */
typedef enum { tt_CONST, tt_OPER, tt_ID } TokenType;
/* виды операций: сложение, вычитание, умножение, деление, левая и правая скобки */
typedef enum { op_ADD, op_SUB, op_MUL, op_DIV, op_LBR, op_RBR } OperType;
/* максимальная длина имени переменной */
#define MAX_ID_LEN 40
/* тип - лексема */
typedef struct {
TokenType ttype;
unionValue{
/* с лексемой связано одно из следующих значений */
int inum;
OperType otype;
char id[MAX_ID_LEN + 1];
} tvalue;
} Token;
/* перевести текстовую строку (s) в массив лексем (*tokens).
получается массив длиной (*len).
память под выходной массив выделяется внутри функции,
а освобождается вызывающей стороной.
в случае успеха вернуть 0, иначе какой-либо код ошибки. */
int tokenize(const char *s, Token **tokens, int *len);
/* перевести набор лексем из инфиксного порядка в постфиксный.
память выделяется внутри функции, освобождается вызывающей стороной.
в случае успеха вернуть 0, иначе какой-либо код ошибки. */
int infix2postfix(const Token *infix, int in_len,
Token **postfix, int *out_len);
#endif
Описание работы программы
Структура StrArray:
Состоит из двух элементов: динамического массива строк (** item) и переменной (counti), в которую записывается количество строк в массиве.
Функция short add_item(struct StrArray* array, char* new_item):
Выделяет память и добавляет новую строку в массив item.
Процедура void free_items(struct StrArray* array):
Освобождает память выделенную под массив item.
Процедура void GetItems(const char* s, struct StrArray *InputItems):
Принимает строку sи выбирает из нее «слова/данные» разделенные любым кол-вом пробелов или символов табуляций. Затем записывает выделенные «слова/данные» в массивInputItems.item.
Инициализируем индекс CurCh для обхода строк
Инициализируем флаг separat которые показывает что был встречен разделитель (символ пробела или таба)
Инициализируем строку в которой будем собирать текущее слово
Очищаем CurItem
Инициализируем индекс(CurCh_inNew) который будет считать кол-во символов в новом найденном слове
-
Входим цикл, который обходит по символьно строку CurCh, до тех пор пока она не кончится
В случае нахождения разделителя устанавливаем separat = 1
-
Если данный символ не разделитель
-
Если separat == 1, то обнуляем его
если кол-во символов в новом слове не равняется 1, то запишем его в массив с помощью add_item.
Установим CurCh_inNew = 0
Очистим CurItem
-
Добавим текущий символ в CurItem
Если CurItem не пуста, то добавим ее в InputItems
Функция int tokenize(const char *s, Token **tokens, int *len):
Принимает строку(s) и преобразует ее в массив (**tokens).
Инициализируем структуру ItemsArray для хранения слов выделенных из строки
С помощью GetItems получим в структуру ItemsArray слова
Инициализируем массив токенов
-
Входим в цикл обходящий все слова в ItemsArray
Устанавливаем указатель на теще слово
Выделяем память под новый токен
Устанавливаем указатель на текущий токен
-
Условие: если в слове один символ и первый символ в слове == + или – или * или / ( или ) то
Записать в структуру Token что текущий символ является оператором (tt_OPER)
Сохранить слово в Token
-
Если нет, то
-
Заводим индекс CurChar = 1
-
Если первый символ в слове является числом
Входим в цикл читающий посимвольно слово, до конца
-
Условие: если текущий символ не является числом,то
Освободить память ItemsArray
Выйти с кодом ошибки -1
Записать в структуру Token что текущий символ является числом (tt_CONST)
Преобразовать слово в число и сохранить в Token
-
Если нет, то проверяем является ли текущий символ алфавитным. Если да, то
Входим в цикл читающий посимвольно слово, до конца
-
Условие если текущий символ не алфавитный и не является числом, то
Освободить память ItemsArray
Выйти с кодом ошибки -1
Записать в структуру Token что текущий символ является переменной (tt_ID)
Сохранить слово в Token
-
Если нет, то
Освободить память ItemsArray
Выйти с кодом ошибки -1
-
-
Освободить память ItemsArray
Структура TokensDArray:
Состоит из двух элементов: динамического массива токенов (*items) и переменной (count), в которую записывается количество токенов в стеке.
Функция short push(TokensDArray *stack, const Token *token):
Выделяет память под новый элемент стека и кладет токен(*token) в конец.
Функция short pop(TokensDArray *stack, Token **TokensArray, int *len):
Вынимает токен из конца стека и возвращает его.
Функция short out_UntilBrac(TokensDArray *stack, Token **TokensArray, int *len):
Вынимает последний токен из стека(*stack) и записывает его в массив токенов(**TokensArray).
Выполнение таких операции продолжается до нахождения открывающей строчки.
Функция int infix2postfix(const Token *infix, int in_len, Token **postfix, int *out_len):
Преобразование массива с инфиксной формой(*infix)в массив с постфиксной формой(**postfix).
Инициализируем массив токенов
Инициализируем структуру для стека
Инициализируем массив стека
-
Входим в цикл, проходящий по всем токенам в массиве с инфиксной формой
-
Условие. Если текущий токен является оператором, то
Если текущий токен == (, то поместить токен в стек с помощью push
Если текущий токен == ), то вывести все до открывающей скобки в выходную последовательность с помощью out_UntilBrac
-
Если ни «(» ни «)», то
-
Если токен == «+» или «-»,то
-
Входим в цикл, выполняющийся до тех пор пока текущий токен == «+» или «-» или «*» или «/»
Вынимаем токен из стека в выходную последовательность
Помещаем токен в стек
-
-
Если нет, то если токен == «*» или «/»
-
Входим в цикл, выполняющийся до тех пор пока текущий токен == «*» или «/»
Вынимаем токен из стека в выходную последовательность
Помещаем токен в стек
-
Если нет, то выходим с кодом ошибки -1
-
-
Если нет, то если текущий токен является числом или перемнной, то
Выделяем память под новый токен в массиве с постфиксной формой
Записываем теущий токен из массиво с инфиксной формой в массив с постфиксной
Если нет, то выходим с кодом ошибки -2
-
Выводим все оставшиеся токены в стеке в массив с постфиксной формой с помощью out_everyth
Освобождаем память из под стека