Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

КУРСОВАЯ код

.txt
Скачиваний:
0
Добавлен:
06.10.2025
Размер:
14.9 Кб
Скачать
#include <iostream>
#include <windows.h>
#include <fstream>
#include <string>
#include <iomanip>

using namespace std;

const int MAX_VERTICES = 50;

struct Node {
    int vertex;
    int weight;
    Node* next;
};

//ребро
struct Edge {
    int v1, v2; //вершины
    int weight; //длина пути
};

//граф
struct Graph {
    int V, E;  //кол-во вершин и ребер
    Edge edges[50];  //массив ребер
};


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


// Функция для поиска корня поддерева
// Для каждой вершины графа создается массив связанных с ней ребер,
// где каждое ребро представляется структурой Node.
// При поиске корня поддерева мы идем по связанным с вершиной ребрам до тех пор,
// пока не найдем вершину, у которой нет родителя (parent[i] == -1).
// Это и будет корень поддерева.

int findParent(int parent[], int i) {
    if (parent[i] == -1) {
        return i;
    }
    return findParent(parent, parent[i]);
}


//Функция для объединения двух подмножеств
// При объединении подмножеств мы находим корни каждого подмножества,
// сравниваем их ранги и присоединяем одно подмножество к другому.

void unionSets(int parent[], int rank[], int x, int y) {
    int xroot = findParent(parent, x);
    int yroot = findParent(parent, y);

    if (rank[xroot] < rank[yroot]) {
        parent[xroot] = yroot;
     else if (rank[xroot] > rank[yroot]) {
        parent[yroot] = xroot;
     else {
        parent[yroot] = xroot;
        rank[xroot]++;
    }

// Функция для построения минимального остовного дерева алгоритмом Крускала
// Вначале создаем массив родителей для каждой вершины и инициализируем его значением -1,
// что означает, что у каждой вершины нет родителя.
// Также создаем массив рангов для каждой вершины и инициализируем его значением 0.
// Затем сортируем массив ребер по возрастанию весов.
// Далее проходим по отсортированному массиву ребер и добавляем их в остовное дерево,
// если они не образуют цикл с уже добавленными ребрами.

//Алгортм Крускала
void Graph kruskalMST(Graph graph) {
    Graph MST;
    MST.V = graph.V;
    MST.E = 0;

    int parent[graph.V];
    int rank[graph.V];

    for (int i = 0; i < graph.V; i++) {
        parent[i] = -1;
        rank[i] = 0;
    }

    Edge edges[graph.E];
    for (int i = 0; i < graph.E; i++) {
        edges[i] = graph.edges[i];
    }

    std::sort(edges, edges + graph.E, [](Edge a, Edge b) {
        return a.weight < b.weight;
    );

    for (int i = 0; i < graph.E; i++) {
        int x = findParent(parent, edges[i].v1);
        int y = findParent(parent, edges[i].v2);

        if (x != y) {
            MST.edges[MST.E++] = edges[i];
            unionSets(parent, rank, x, y);
        }
    }

    return MST;
}

//чтение матрицы смежности из файла
int readMatrix(const string& filename, int matrix[50][50], char graph[50]) {
    int size = 0;
    string s;
    ifstream file(filename);
    if (file.is_open()) {
        getline(file, s);
        //чтение графов
        for (int i = 0; i < s.length(); i++) {
            if (s[i] != ' ') {
                graph[size] = s[i];
                size++;
            }
        }
        //чтение матрицы смежности
        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                file >> matrix[i][j];
                if (matrix[i][j] < 0) {
                    return 0;
                }
            }
        }
        file.close();
    }
    else {
        cout << "Ошибка открытия файла!" << std::endl;
    }
    return size;
}

//проверка матрицы 
int isCorrectMatrix(int matrix[50][50], int ver)
{
    int edge = 0;
    //проверяем, что все элементы на главной диагонали равны нулю
    for (int i = 0; i < ver; i++) {
        if (matrix[i][i] != 0) {
            return 0;
        }
    }
    //проверяем, что матрица симметрична относительно главной диагонали
    for (int i = 0; i < ver; i++) {
        for (int j = i + 1; j < ver; j++) {
            if (matrix[i][j] != matrix[j][i]) {
                return 0;
            }
            else if (matrix[i][j] != 0) {
                edge++;
            }
        }
    }
    return edge;
}

//Создание списка смежности
void createAdjacencyList(Graph* graph, char vertex[50], Node* adjList[50]) {
    for (int i = 0; i < graph->V; i++) {
        adjList[i] = nullptr;
    }

    for (int i = 0; i < graph->E; i++) {
        int v1 = graph->edges[i].v1;
        int v2 = graph->edges[i].v2;
        int weight = graph->edges[i].weight;

        Node* newNode = new Node;
        newNode->vertex = v2;
        newNode->weight = weight;
        newNode->next = adjList[v1];
        adjList[v1] = newNode;

        newNode = new Node;
        newNode->vertex = v1;
        newNode->weight = weight;
        newNode->next = adjList[v2];
        adjList[v2] = newNode;
    }

    // Вывод списка смежности
    cout << "Список смежности:" << endl;
    for (int i = 0; i < graph->V; i++) {
        cout << vertex[i] << " -> ";
        Node* current = adjList[i];
        while (current != nullptr) {
            cout << vertex[current->vertex] << "(" << current->weight << ") ";
            current = current->next;
        }
        cout << endl;
    }
}

// Функция для создания матрицы инцидентности
void createIncidenceMatrix(Graph graph) {
    int incidenceMatrix[graph.V][graph.E];

    // Инициализируем матрицу инцидентности нулями
    for (int i = 0; i < graph.V; i++) {
        for (int j = 0; j < graph.E; j++) {
            incidenceMatrix[i][j] = 0;
        }
    }

    // Заполняем матрицу инцидентности единицами и минус единицами
    for (int i = 0; i < graph.E; i++) {
        incidenceMatrix[graph.edges[i].v1][i] = 1;
        incidenceMatrix[graph.edges[i].v2][i] = -1;
    }

    // Выводим матрицу инцидентности на экран
    for (int i = 0; i < graph.V; i++) {
        for (int j = 0; j < graph.E; j++) {
            std::cout << incidenceMatrix[i][j] << " ";
        }
        std::cout << std::endl;
    }

// Функция для обхода в глубину
void DFS(int vertex, bool visited[], Node* adjacencyList[]) {
    visited[vertex] = true;
    std::cout << vertex << " ";

    Node* currentNode = adjacencyList[vertex];
    while (currentNode != nullptr) {
        int adjacentVertex = currentNode->vertex;
        if (!visited[adjacentVertex]) {
            DFS(adjacentVertex, visited, adjacencyList);
        }
        currentNode = currentNode->next;
    }

// Функция для обхода в глубину всего графа
void depthFirstTraversal(Graph graph) {
    bool visited[graph.V];
    for (int i = 0; i < graph.V; i++) {
        visited[i] = false;
    }

    Node* adjacencyList[graph.V];
    for (int i = 0; i < graph.V; i++) {
        adjacencyList[i] = nullptr;
    }

    // Создаем список смежности
    for (int i = 0; i < graph.E; i++) {
        int v1 = graph.edges[i].v1;
        int v2 = graph.edges[i].v2;

        // Добавляем ребро в список смежности первой вершины
        Node* newNode1 = new Node;
        newNode1->vertex = v2;
        newNode1->weight = graph.edges[i].weight;
        newNode1->next = adjacencyList[v1];
        adjacencyList[v1] = newNode1;

        // Добавляем ребро в список смежности второй вершины
        Node* newNode2 = new Node;
        newNode2->vertex = v1;
        newNode2->weight = graph.edges[i].weight;
        newNode2->next = adjacencyList[v2];
        adjacencyList[v2] = newNode2;
    }

    // Обходим все вершины графа в глубину
    for (int i = 0; i < graph.V; i++) {
        if (!visited[i]) {
            DFS(i, visited, adjacencyList);
        }
    }

// Функция для обхода в ширину
void breadthFirstTraversal(Graph graph, int startVertex) {
    bool visited[graph.V];
    for (int i = 0; i < graph.V; i++) {
        visited[i] = false;
    }

    Node* adjacencyList[graph.V];
    for (int i = 0; i < graph.V; i++) {
        adjacencyList[i] = nullptr;
    }

    // Создаем список смежности
    for (int i = 0; i < graph.E; i++) {
        int v1 = graph.edges[i].v1;
        int v2 = graph.edges[i].v2;

        // Добавляем ребро в список смежности первой вершины
        Node* newNode1 = new Node;
        newNode1->vertex = v2;
        newNode1->weight = graph.edges[i].weight;
        newNode1->next = adjacencyList[v1];
        adjacencyList[v1] = newNode1;

        // Добавляем ребро в список смежности второй вершины
        Node* newNode2 = new Node;
        newNode2->vertex = v1;
        newNode2->weight = graph.edges[i].weight;
        newNode2->next = adjacencyList[v2];
        adjacencyList[v2] = newNode2;
    }

    // Очередь для обхода в ширину
    std::queue<int> q;

    visited[startVertex] = true;
    q.push(startVertex);

    while (!q.empty()) {
        int currentVertex = q.front();
        q.pop();
        std::cout << currentVertex << " ";

        Node* currentNode = adjacencyList[currentVertex];
        while (currentNode != nullptr) {
            int adjacentVertex = currentNode->vertex;
            if (!visited[adjacentVertex]) {
                visited[adjacentVertex] = true;
                q.push(adjacentVertex);
            }
            currentNode = currentNode->next;
        }
    }

void printSeparator() {
    cout << setfill('-') << setw(50) << "-" << setfill(' ') << endl;
}

void displayMenu() {
    printSeparator();
    cout << "Меню:" << endl;
    cout << "1. Выполнить обход графа" << endl;
    cout << "2. Вывести список смежности" << endl;
    cout << "3. Вывести матрицу инцидентности" << endl;
    cout << "4. Выйти из программы" << endl;
    printSeparator();
}

void performTraversal(Graph* graph, char vertex[], Node* adjList[], bool isDFS) {
    int n = -1;
    cout << "С какой вершины провести обход?" << endl;
    while (n < 0) {
        char w;
        cin >> w;
        for (int i = 0; i < graph->V; i++) {
            if (w == vertex[i]) {
                n = i;
                break;
            }
        }
        if (n == -1) {
            cout << "Неверное значение" << endl;
        }
    }
    cout << endl;
    DFS(graph, n, vertex, adjList);
    BFS(graph, n, vertex, adjList);
    cout << endl;
}

void printAdjacencyMatrix(Graph* graph, char vertex[50], int adjacencyMatrix[MAX_VERTICES][MAX_VERTICES]) {
    cout << "Матрица смежности:" << endl;
    printSeparator();
    for (int i = 0; i < graph->V; i++) {
        for (int j = 0; j < graph->V; j++) {
            cout << setw(2) << adjacencyMatrix[i][j] << " ";
        }
        cout << endl;
    }
    printSeparator();
}

int main() {
    setlocale(LC_ALL, "rus");
    SetConsoleOutputCP(1251);
    SetConsoleCP(1251);

    Graph graph;
    string filename = "graph.txt";
    int matrix[50][50];
    char vertex[50];
    int edge = 0, ver = 0;

    ver = readMatrix(filename, matrix, vertex);
    edge = isCorrectMatrix(matrix, ver);

    if (!ver || !edge) {
        cout << "Неверная запись в файле" << endl;
    }
    else {
        cout << "Матрица смежности:" << endl;
        printSeparator();
        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;
        }
        printSeparator();
        graph.V = ver;
        graph.E = edge;
        int q = 0;
        for (int i = 0; i < ver; i++) {
            for (int j = i + 1; j < ver; j++) {
                if (matrix[i][j] != 0) {
                    graph.edges[q].v1 = i;
                    graph.edges[q].v2 = j;
                    graph.edges[q].weight = matrix[i][j];
                    q++;
                }
            }
        }

        cout << endl;
        Kruskal(&graph, vertex);

        Node* adjList[50];

        int incidenceMatrix[MAX_VERTICES][MAX_VERTICES];

        while (true) {
            displayMenu();

            int choice;
            cout << "Выберите действие (1-4): ";
            cin >> choice;

            switch (choice) {
            case 1:
                performTraversal(&graph, vertex, adjList, true);  // true для DFS
                break;
            case 2:
                createAdjacencyList(&graph, vertex, adjList);
                break;
            case 3:
                createIncidenceMatrix(&graph, vertex, incidenceMatrix);
                break;
            case 4:
                cout << "Программа завершена." << endl;
                return 0;
            default:
                cout << "Неверный выбор. Попробуйте еще раз." << endl;
            }
        }
    }
    return 0;
}
Соседние файлы в предмете Алгоритмы и системы данных