Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Курсовая аисд.docx
Скачиваний:
0
Добавлен:
06.10.2025
Размер:
724.22 Кб
Скачать

10. Оценка общей временной сложности

Таблица 1

Функция

Временная сложность

Создание графа (массив рёбер)

O(n)

Обработка

O(n)

Сортировка ребер по возрастанию весов

O(n log f(n) )

Создание минимального остовного дерева

O(1)

Сортировка ребер в лексикографическом порядке

O(n^2)

Вывод минимального остовного дерева

O(n)

Заключение

В результате работы алгоритма получается минимальное остовное дерево, которое является подмножеством исходного графа и содержит все вершины исходного графа. Вес минимального остовного дерева будет минимальным среди всех возможных остовных деревьев данного графа.

В заключении курсовой работы можно отметить, что успешная реализация алгоритма Крускала позволила найти минимальное остовное дерево в графе. Реализация этого алгоритма подтверждает знания в области сортировки (используя сортировку пузырьком для ребер), обхода графов (через функции Find и Merge для определения и добавления ребер в остовное дерево) и хранения графов (в данном случае, представление графа в виде массива родительских вершин).

Список использованных источников

  1. Дискретная математика: учебник для студентов вузов / С. Н. Поздняков, С. В. Рыбин. Москва: Издательский центр «Академия», 2008. 448 с.

  2. Marcoutte.me. URL: https://markoutte.me/students/algos-final-task/

  3. Ru.Wikipedia.org.URL: https://ru.wikipedia.org/wiki/

Приложение а. Код программы

#include <iostream>

#include <windows.h>

#include <fstream>

#include <string>

#include <conio.h>

#include <sstream>

using namespace std;

void ShowMenu(int str)

{

cout << "Выберите действие:" << endl;

printf("%s1. Вывод списка смежности\n", str == 1 ? " => " : " ");

printf("%s2. Вывод матрицы инцидентности\n", str == 2 ? " => " : " ");

printf("%s3. Обход в глубину\n", str == 3 ? " => " : " ");

printf("%s4. Обход в ширину\n", str == 4 ? " => " : " ");

printf("%s5. Алгоритм Крускала\n", str == 5 ? " => " : " ");

printf("%s6. Выход\n", str == 6 ? " => " : " ");

}

struct Node

{

int data;

Node* next;

Node(int data)

{

this->data = data;

this->next = nullptr;

}

};

//Ребро

struct Edge

{

int first, end; //вершины

int weight; //вес

};

//Функция для чтения матрицы смежности из файла

int readAdjacencyMatrix(const string& filename, int matrix[50][50], string graph[50], bool correct)

{

int size = 0;

string s;

ifstream file(filename);

if (file.is_open())

{

getline(file, s);

istringstream iss(s);

while (iss >> graph[size]) {

size++;

}

for (int i = 0; i < size; i++)

{

for (int j = 0; j < size; j++)

{

file >> matrix[i][j];

if (matrix[i][j] < 0)

{

cout << "Выход за границы допустимых значений";

correct = false;

return 0;

}

}

}

file.close();

}

else

{

cout << "Невозможно открыть файл" << endl;

}

return size;

}

//Проверка на симметричность

int isCorrectMatrix(int matrix[50][50], int ver, bool correct)

{

int edge = 0;

for (int i = 0; i < ver; i++) //все элементы на главной диагонали = 0

{

if (matrix[i][i] != 0 || matrix[i][i] > 1023) //диапазон веса = [0;1023]

{

cout << "Выход за границы допустимых значений";

correct = false;

return 0;

}

}

for (int i = 0; i < ver; i++)

{

for (int j = i + 1; j < ver; j++)

{

if (matrix[i][j] != matrix[j][i] || matrix[i][j] > 1023 || matrix[i][j] < 0)

{

cout << "Ошибка ввода матрицы";

correct = false;

return 0;

}

else if (matrix[i][j] != 0)

{

edge++;

}

}

}

return edge;

}

//Функция для поиска корня поддерева

int findParent(int parent[], int i) {

while (parent[i] != -1)

i = parent[i];

return i;

}

//Функция для объединения двух подмножеств

void unionSets(int parent[], int x, int y) {

int rootX = findParent(parent, x);

int rootY = findParent(parent, y);

parent[rootX] = rootY;

}

class List

{

public:

Node* head, * tail;

public:

List()

{

this->head = this->tail = nullptr;

}

~List()

{

while (head != nullptr)

pop_front();

}

Node* push_back(int data)

{

Node* ptr = new Node(data);

if (tail != nullptr)

tail->next = ptr;

if (head == nullptr)

head = ptr;

tail = ptr;

return ptr;

}

void pop_front()

{

if (head == nullptr) return;

Node* ptr = head->next;

delete head;

head = ptr;

}

};

//Граф

struct Graph

{

int V, E; //кол-во вершин и ребер

Edge* edges; //массив ребер

List* adjacencyList; //массив связных списков

};

struct Queue

{

Node* front, * rear;

Queue()

{

this->front = this->rear = nullptr;

}

~Queue()

{

while (front != nullptr)

dequeue();

}

void enqueue(int data)

{

Node* ptr = new Node(data);

if (rear != nullptr)

rear->next = ptr;

if (front == nullptr)

front = ptr;

rear = ptr;

}

void dequeue()

{

if (front == nullptr) return;

Node* ptr = front->next;

delete front;

front = ptr;

if (front == nullptr)

rear = nullptr;

}

bool isEmpty() const

{

return front == nullptr;

}

int getFront() const

{

if (front != nullptr)

return front->data;

return -1;

}

};

//Вывод списка смежности

void printAdjacencyList(const Graph& graph, const string* vertex)

{

cout << "Текущий список смежности:" << endl;

for (int i = 0; i < graph.V; ++i)

{

cout << vertex[i] << ": ";

Node* current = graph.adjacencyList[i].head;

while (current != nullptr)

{

cout << vertex[current->data] << " ";

current = current->next;

}

cout << endl;

}

}

//Вывод матрицы инцидентности

void printIdentityMatrix(const Graph& graph)

{

cout << "Матрица инцидентности:" << endl;

for (int i = 0; i < graph.V; ++i)

{

for (int j = 0; j < graph.E; ++j)

{

if (i == graph.edges[j].first || i == graph.edges[j].end)

cout << "1 ";

else

cout << "0 ";

}

cout << endl;

}

}

// Функция для сравнения по лексикографическому порядку

bool VertexAlpha(const Edge& e1, const Edge& e2, const string* vertex) {

if (vertex[e1.first] > vertex[e2.first] || (vertex[e1.first] == vertex[e2.first] && vertex[e1.end] > vertex[e2.end]))

return true;

return false;

}

//Сортировка пузырьком

void bubbleSort(Edge arr[], int n)

{

for (int i = 0; i < n - 1; ++i)

{

for (int j = 0; j < n - i - 1; ++j)

{

if (arr[j].weight > arr[j + 1].weight)//сравнение по весу

{

Edge temp = arr[j];

arr[j] = arr[j + 1];

arr[j + 1] = temp;

}

}

}

}

//Cортировка по лексикографическому порядку

void sortABC(Edge arr[], int n, const string* vertex) {

for (int i = 0; i < n - 1; ++i) {

for (int j = 0; j < n - i - 1; ++j) {

if (VertexAlpha(arr[j], arr[j + 1], vertex)) {

Edge temp = arr[j];

arr[j] = arr[j + 1];

arr[j + 1] = temp;

}

}

}

}

//Алгоритм Крускала

void AlgKruscal(Graph& graph, const string* vertex) {

bubbleSort(graph.edges, graph.E);

int* parent = new int[graph.V];

fill(parent, parent + graph.V, -1);

Edge* resultEdges = new Edge[graph.V - 1];

int resultEdgesCount = 0;

cout << "Минимальный остов:" << endl;

int totalWeight = 0;

for (int i = 0; i < graph.E; ++i) {

int root1 = findParent(parent, graph.edges[i].first);

int root2 = findParent(parent, graph.edges[i].end);

if (root1 != root2) {

resultEdges[resultEdgesCount++] = graph.edges[i];

unionSets(parent, root1, root2);

totalWeight += graph.edges[i].weight;

}

}

//cортировка рёбер в алфавитном порядке

sortABC(resultEdges, resultEdgesCount, vertex);

//Вывод рёбер остовного дерева в алфавитном порядке

for (int i = 0; i < resultEdgesCount; ++i) {

cout << vertex[resultEdges[i].first] << " " << vertex[resultEdges[i].end] << " " << resultEdges[i].weight << " " << endl;

}

cout << "Длина минимального остова: ";

cout << totalWeight << endl;

//oсвобождение памяти

delete[] parent;

delete[] resultEdges;

}

//Доп функция обхода в глубину

void add_DFS(const Graph& graph, int v, bool visited[], const string* vertex) {

visited[v] = true;

cout << vertex[v] << " ";

Node* current = graph.adjacencyList[v].head;

while (current != nullptr) {

if (!visited[current->data]) {

add_DFS(graph, current->data, visited, vertex);

}

current = current->next;

}

}

//Функция для полного обхода в глубину (DFS)

void depthFirstSearch(const Graph& graph, int startVertex, const string* vertex) {

bool* visited = new bool[graph.V];

fill(visited, visited + graph.V, false);

cout << "Результат обхода DFS с " << vertex[startVertex] << ": ";

add_DFS(graph, startVertex, visited, vertex);

cout << endl;

delete[] visited;

}

//Функция для полного обхода в ширину (BFS)

void breadthFirstSearch(const Graph& graph, int startVertex, const string* vertex) {

bool* visited = new bool[graph.V];

fill(visited, visited + graph.V, false);

cout << "Результат обхода BFS с " << vertex[startVertex] << ": ";

Queue q;

visited[startVertex] = true;

q.enqueue(startVertex);

while (!q.isEmpty()) {

int v = q.getFront();

q.dequeue();

cout << vertex[v] << " ";

Node* current = graph.adjacencyList[v].head;

while (current != nullptr) {

if (!visited[current->data]) {

visited[current->data] = true;

q.enqueue(current->data);

}

current = current->next;

}

}

cout << endl;

delete[] visited;

}

// Функция для преобразования символа в номер вершины

int charToInt(string vertex[], int size, string c) {

for (int i = 0; i < size; ++i) {

if (vertex[i] == c) {

return i;

}

}

return -1;

}

int main()

{

setlocale(0, "");

int str = 1, ind = 6, usl = 0, com;

Graph graph;

string filename = "file.txt";

int matrix[50][50];

string vertex[50];

bool correct = true;

int edge = 0, ver = 0;

while (usl == 0) {

system("cls");

cout << "КУРСОВАЯ РАБОТА: Алгоритм Крускала" << endl;

ver = readAdjacencyMatrix(filename, matrix, vertex, correct);

edge = isCorrectMatrix(matrix, ver, correct);

if (!ver || !edge || correct == false)

{

cout << endl << "Неверная запись в файле" << endl;

return 0;

}

else

{

cout << "Матрица смежности, полученная из файла:" << endl;

for (int i = 0; i < ver; i++)

{

cout << vertex[i] << " ";

}

cout << endl;

for (int i = 0; i < ver; i++)

{

for (int j = 0; j < ver; j++)

{

cout << matrix[i][j] << " ";

}

cout << endl;

}

graph.V = ver;

graph.E = edge;

graph.edges = new Edge[edge];

graph.adjacencyList = new List[ver];

int edgeIndex = 0;

for (int i = 0; i < graph.V; ++i)

{

for (int j = i + 1; j < graph.V; ++j)

{

if (matrix[i][j] != 0)

{

// Добавляем ребро в массив рёбер

graph.edges[edgeIndex].first = i;

graph.edges[edgeIndex].end = j;

graph.edges[edgeIndex].weight = matrix[i][j];

// Добавляем в список смежности для обеих вершин

graph.adjacencyList[i].push_back(j);

graph.adjacencyList[j].push_back(i);

++edgeIndex;

}

}

}

cout << '\n';

ShowMenu(str);

com = _getch();

if (com >= '1' && com <= '6') str = com - '0';

if (com == 224) {

com = _getch();

switch (com) {

case 72:

str = (str - 1 + 5) % 6 + 1;

break;

case 80:

str = (str - 1 + 1) % 6 + 1;

break;

}

}

if (com == 13)

{

switch (str)

{

case 1://Вывод списка смежности

{

system("cls");

printAdjacencyList(graph, vertex);

system("Pause");

break;

}

case 2://Вывод матрицы инцидентности

{

system("cls");

printIdentityMatrix(graph);

system("Pause");

break;

}

case 3://Обход в глубину

{

string startVertex;

cout << endl << "С какой вершины начать обход? (";

for (int i = 0; i < graph.V - 1; ++i) {

cout << vertex[i] << ", ";

}

cout << vertex[graph.V - 1] << "):"<<endl;

cin >> startVertex;

int startVertexIndex = charToInt(vertex, graph.V, startVertex);

if (startVertexIndex != -1)

{

// Вызов обхода в глубину (DFS)

depthFirstSearch(graph, startVertexIndex, vertex);

}

else

{

cout << "Неверный ввод" << endl;

}

system("Pause");

break;

}

case 4://Обход в ширину

{

string startVertex;

cout << endl << "С какой вершины начать обход? (";

for (int i = 0; i < graph.V - 1; ++i) {

cout << vertex[i] << ", ";

}

cout << vertex[graph.V - 1] << "):" << endl;

cin >> startVertex;

int startVertexIndex = charToInt(vertex, graph.V, startVertex);

if (startVertexIndex != -1)

{

breadthFirstSearch(graph, startVertexIndex, vertex);

}

else

{

cout << "Неверный ввод" << endl;

}

system("Pause");

break;

}

case 5://Алгоритм Крускала

{

system("cls");

AlgKruscal(graph, vertex);

system("pause");

break;

}

case 6://Выход

{

system("cls");

return 0;

break;

}

}

}

}

}

}

Соседние файлы в предмете Алгоритмы и системы данных