Министерство образования и науки Российской Федерации
НОВОСИБИРСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ
КАФЕДРА ПРИКЛАДНОЙ МАТЕМАТИКИ
Курсовая работа
по практикуму на ЭВМ: структуры данных и алгоритмы
Факультет: прикладной математики и информатики
Группа: ПМИ-52
Студентка: Рыльская О.С.
Преподаватель: Тракимус Ю.В.
Новосибирск
2016
Условие задачи
Найти все вершины заданного графа, недостижимые от заданной его вершины.
Анализ задачи
Исходные данные:
множество рёбер
графа.
заданная вершина.
Результат:
множество всех
вершин, недостижимых из вершины
Формальная постановка задачи:
В ориентированном невзвешенном графе найти все вершины, до которых не существует пути из указанной вершины.
Решение задачи сводится к тому, что нужно применить любой из обходов графа и просмотреть по окончанию обхода информацию о том, какие вершины были пройдены, а какие нет, эту информацию можно извлечь, например, из массива, который отвечает за раскраску вершин во время обхода.
Основные подзадачи для решения общей задачи:
Ввод графа
Осуществление обхода графа (был выбран обход в ширину)
Просмотр массива с данными о раскрашенных вершинах.
Структуры данных, используемые для представления исходных данных и результатов задачи
Входные данные:
Внешнее представление:
<информация о графе> ::= <список ребер>
<список ребер> ::= <пара вершин> | <список ребер>
<Пара вершин> ::= <вершина> пробел <вершина>
<вершина> ::= натуральное число, строго меньшее количества вершин в графе.
Внутреннее представление:
Используется списки смежности.
struct AdjacencyList {
int vertexNumber;
AdjacencyList *next;
};
struct Node {
int vertexNumber;
AdjacencyList *adjList;
Node *next, *prev;
};
struct Graph {
Node *listOfAdjacency;
int amountVertices;
};
Выходные данные:
Внешнее представление:
<список вершин> ::= <вершина> | <список вершин>
<вершина> ::= натуральное число, строго меньшее количества вершин.
Внутреннее представление:
В программе нет представления выходного списка вершин.
Укрупненный алгоритм решения задачи
Укрупненный алгоритм решения задачи:
{
Ввод информации о графе и составление по введенным данным списков смежности.
Ввод
.
Осуществление
обхода графа в ширину и возвращение
информации о раскрашенных вершинах в
виде массива
.
{
{
Вывести
номер вершины
.
}
}
вывести, что недостижимых вершин нет.
}
Алгоритм обхода графа в ширину:
{
{
}
}
Укрупненный алгоритм ввода графа:
{
}
Структура программы
Текст программы разбит на 3 модуля: source.cpp, graph.h, queue.h
Модуль graph.h содержит описание графа и функции, реализующие операции над графом.
Модуль queue.h содержит описание такого типа данных, как очередь, а также функции, которые реализуют операции над очередью.
source.cpp содержит основную функцию, которая вызывает все остальные необходимые функции и в которой происходит диалог с пользователем.
Описание модуля graph.h
Graph* createEmptyGraph()
Назначение – создание пустого графа.
Результатом является указатель на область памяти, где содержится граф.
void deleteGraph(Graph **G)
Назначение – удаление графа из памяти.
Аргументом является адрес указателя, который содержит адрес области памяти, в которой хранится граф.
Graph* readGraphFromFile(char *pathToFile)
Назначение – чтение графа из файла.
Аргументом является строка, которая содержит путь до файла, в котором хранятся данные о графе.
Результатом является указатель на область памяти, где содержится граф.
void printGraph(Graph *G)
Назначение – вывод графа в консоль.
Аргументом является указатель на область памяти, где содержится граф.
int* BFS(Graph *G, int startVertex)
Назначение – обход графа в ширину.
Первым аргументом является указатель на область памяти, где содержится граф.
Вторым аргументом является номер вершины, с которой необходимо начать обход.
Результатом является указатель на начало массива, в котором хранится информация о раскраске графа после обхода.
void addEdge(Graph *G, int u, int v)
Назначение – добавление ребра в граф.
Первым аргументом является указатель на область памяти, где содержится граф.
Вторым и третьим аргументом являются соответственно начало и конец ребра (номера вершин).
Node* addNode(Node *head, int numberOfVertex)
Назначение – добавление нового элемента в список вершин.
Первым аргументом является указатель на первый элемент списка.
Вторым аргументом является номер добавляемой вершины.
Результатом является указатель на элемент списка, который был создан и добавлен в список вершин.
Node* findNode(Graph *G, int numberOfVertex)
Назначение – нахождение вершины с заданным номером.
Первым аргументом является указатель на граф.
Вторым аргументом является номер вершины, которую надо найти в списке вершин.
Результатом является либо указатель на элемент списка (в случае успеха), либо нулевой указатель (в случае неудачи).
void deleteNodeList(Node **L)
Назначение – удаление списка вершин.
Аргументом является адрес указателя, который указывает на первый элемент списка.
void addAdjacencyNode(AdjacencyList **L, int numberOfAdjVertex)
Назначение – добавление вершины в список смежности.
Первым аргументом является адрес указателя, который указывает на первый элемент списка.
Вторым аргументом является номер вершины, которую необходимо добавить.
AdjacencyList* findAdjacencyNode(Node *L, int numberOfAdjVertex)
Назначение – нахождение смежной вершины с заданным номером.
Первым аргументом является адрес на элемент в списке вершин, в котором будет просматриваться список смежности.
Вторым аргументом является номер вершины, которую необходимо найти.
Результатом является либо указатель на элемент списка смежности (в случае успеха), либо на нулевой указатель (в случае неудачи).
Описание модуля queue.h
Queue* createQueue()
Назначение – создать пустую очередь.
Результатом является указатель на область памяти, в которой содержится очередь.
int isEmpty(Queue *Q)
Назначение – проверка очередь на наличие элементов в ней.
Аргументом является указатель на область памяти, в которой содержится очередь.
Результатом является единица, если очередь пуста, или нуль, если очередь не пуста.
int pop(Queue *Q, int *val)
Назначение – получить элемент из очереди.
Первым аргументом является указатель на область памяти, в которой содержится очередь.
Вторым аргументом является адрес переменной, в которую нужно поместить значение из очереди.
Результатом является единица, если элемент был успешно извлечен, или нуль, если в очереди нет элементов.
void push(Queue *Q, int val)
Назначение – добавить элемент в очередь.
Первым аргументом является указатель на область памяти, в которой содержится очередь.
Вторым аргументом является значение, которое необходимо добавить в очередь.
Структура программы по управлению:
