Стеки: для каждой пары скобок напечатать номера их позиций в тексте - C (СИ)
Формулировка задачи:
В строке записан текст что сбалансированный за круглыми скобками:
<текст>::=<пусто>|<елемент><текст>
<елемент>::=<буква>|(<текст>)
Надо для каждой пары скобок открывающиеся и закрывающиеся напечатать номера их позиций в тексте, упорядочив пары номеров по возрастанию номеров позиций скобок видкриваються.Наприклад, для текста А + (45-F (X)*(B-C)) нужно напечатать 3 17;8 10;12 16.
Решение задачи: «Стеки: для каждой пары скобок напечатать номера их позиций в тексте»
textual
Листинг программы
#include <stdio.h>
#include <stdlib.h>
//#include <assert.h>
typedef struct pair_t
{
int first; // Позиция скобки '('
int second; // Позиция скобки ')'
} TPair;
typedef struct node_t
{
TPair data; // Позиции скобок
struct node_t* next; // Указатель не следующий узел
} TNode;
//-----------------------------------------------------------------------------
// Функция добавления новой группы скобок в стек
TNode* Push(TNode** stack, const TPair data)
{
// Проверка не передан ли NULL
//assert(stack);
// Создаём новый узел
TNode* node = (TNode*) malloc(sizeof(TNode));
// Копируем данные в новый узел
node->data = data;
// Добавляем элемент на вершину стека
node->next = *stack;
*stack = node;
return *stack;
}
//-----------------------------------------------------------------------------
// Функция добавления новой группы скобок. При добавление элементы сразу сортируются.
// Правило сортировки задаётся передаваемой функцией
TNode* PushWithSort(TNode** stack, const TPair data,
int (*func)(const TPair*, const TPair*))
{
// Проверка не передан ли NULL
//assert(stack);
//assert(func);
// Временный узел, в конце функции удаляется.
// Нужен для упрощения алгоритма поиска
TNode* head = (TNode*) malloc(sizeof(TNode));
head->next = *stack;
// Курсор который и будет пробегаться по списку
TNode* cur = head;
// Ищем нужное место
for (; cur->next && (func(&data, &cur->next->data) > 0); cur = cur->next) { ; }
// Добавляем указанную позицию наше значение
Push(&cur->next, data);
*stack = head->next;
// Удаляем временный вершинный узел
free(head);
return *stack;
}
//-----------------------------------------------------------------------------
// Функция извлечения значения из стека
TPair Pop(TNode** stack)
{
// Проверка не передан ли NULL или пустой стек
//assert(stack);
//assert(*stack);
// Временно сохраняем указатель на верхний узел
TNode* node = *stack;
// Спускаемся к следующему элементу
*stack = node->next;
// Сохраняем значение удаляемого узла
TPair data = node->data;
// Удаляем узел
free(node);
return data;
}
//-----------------------------------------------------------------------------
// Функция удаления всех элементов стека
void Clear(TNode** stack)
{
// Проверка не передан ли NULL
//assert(stack);
// Пока есть элемент в стеке
while (*stack)
{
// Извлекаем элемент из стека
Pop(stack);
}
}
//-----------------------------------------------------------------------------
// Функция сравнения двух значений типа TPair. Функция используется
// в качестве параметра функцией PushWithSort.
int CompareFirst(const TPair* a, const TPair* b)
{
return (a->first - b->first);
}
//-----------------------------------------------------------------------------
// Функция выводит в стандартный поток вывода все элементы стека
void Print(const TNode* stack)
{
// Перебираем все элементы стека и выводим их
for (; stack; stack = stack->next)
{
printf("%d %d; ", stack->data.first, stack->data.second);
}
printf("\n");
}
//-----------------------------------------------------------------------------
// Функция находит в выражении все открывающиеся и закрывающиеся скобки и
// выводит их координаты по порядку (по пере их появления)
void PrintsPosBreckets(const char* str)
{
//assert(str);
// Временный стек хранящий текущие позиции скобок
TNode* temp = NULL;
// Результирующий список, хранящий позиции скобок в отсортированном виде
TNode* result = NULL;
// Вспомогательная переменная
TPair data;
// Позиция в выражении
int pos = 0;
// Перебираем все элементы выражения
for (; *str; ++str)
{
pos++;
// Проверяем, не является ли скобкой
switch (*str)
{
case '(':
// Сохраняем позицию открывающейся скобки, и добавляем
// позицию во временный стек
data.first = pos;
data.second = -1;
Push(&temp, data);
break;
case ')':
// Извлекаем из временного стека позицию последней открывающейся
// скобки, добавляем позицию закрывающейся, и добавляем эти две
// координаты в результирующий список. Используем для добавления
// функцию добавления с сортировкой, т.е. при добавлении элемент
// будет добавляться не на вершину стека, а туда, где не будет выполнять
// функция CompareFirst
data = Pop(&temp);
data.second = pos;
PushWithSort(&result, data, CompareFirst);
break;
}
}
// Печатаем результирующий список
Print(result);
// Удаляем все элементы списка
Clear(&result);
}
//-----------------------------------------------------------------------------
int main()
{
const char CExpression[] = "(A+(45-F(X)*(B-C)))*Z";
printf("%s\n", CExpression);
PrintsPosBreckets(CExpression);
//system("pause");
return 0;
}
Объяснение кода листинга программы
- Структура данных
pair_tпредставляет собой пару значений типа int, обозначающих позиции скобок '(' и ')'. - Структура данных
node_tпредставляет собой узел стека, содержащий пару значений типа TPair и указатель на следующий узел. - Функция Push добавляет новую группу скобок в стек. Проверяет не NULL указатель на стек, создает новый узел, копирует данные в новый узел, добавляет элемент на вершину стека и возвращает указатель на вершину стека.
- Функция PushWithSort добавляет новую группу скобок в стек, используя переданную функцию сравнения для определения места добавления. Проверяет не NULL указатель на стек и функцию сравнения, создает временный узел, добавляет элемент на вершину стека, удаляет временный узел.
- Функция Pop извлекает значение из стека, проверяет не пустой ли стек, сохраняет указатель на верхний узел, спускается к следующему элементу, сохраняет значение удаляемого узла, удаляет узел и возвращает извлеченное значение.
- Функция Clear удаляет все элементы стека.
- Функция CompareFirst сравнивает два значения типа TPair по первому значению.
- Функция Print выводит все элементы стека в стандартный поток вывода.
- Функция PrintsPosBreckets находит в выражении все открывающиеся и закрывающиеся скобки и выводит их координаты по порядку. Использует стек для хранения текущих позиций скобок и добавляет позиции в отсортированный результирующий список.
- В main() определяется константное выражение
CExpression. Выводится это выражение, затем вызывается функция PrintsPosBreckets.