std :: bad_allo c при расчете дижкстра для большого набора данных - PullRequest
0 голосов
/ 05 января 2020

Я пытаюсь найти кратчайший путь для большого графа, используя алгоритм Дейкстры. Проблема в том, что когда я выполняю программу на CLion, я получаю std :: bad allo c, всегда на узле 491, однако, когда я пытаюсь сделать то же самое на моей Ubuntu VM, я получаю ядро ​​сбрасываемым с самого начала.

Я новичок в c ++, поэтому мне трудно понять, почему это происходит.

Вот мой код:

Утилиты:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <ctime>

#define INFINITY 9999999

int maxNode = 0;
using namespace std;

vector<int> loadFile(const string &path) {
    vector<int> graph;
    ifstream file;
    file.open(path);
    if (!file.fail()) {
        string line;
        while (getline(file, line)) {
            stringstream ss(line);
            for (int i; ss >> i;) {
                if (i + 1 > maxNode)
                    maxNode = i + 1;
                graph.push_back(i);
                if (ss.peek() == ';')
                    ss.ignore();
            }
        }
        file.close();
    }
    return graph;
}

int **formatGraph(vector<int> inData) {
    int **graph = 0;
    int currentIndex = 0;
    int srcNode = inData[0];
    int dstNode = inData[1];
    int cost = inData[2];
    graph = new int *[maxNode];
    for (int i = 0; i < maxNode; i++) {
        graph[i] = new int[maxNode];
        for (int j = 0; j < maxNode; j++) {
            if (srcNode == i && dstNode == j) {
                graph[i][j] = cost;
                currentIndex++;
                srcNode = inData[currentIndex * 3];
                dstNode = inData[currentIndex * 3 + 1];
                cost = inData[currentIndex * 3 + 2];
                //printf("%d %d\n", i, j);
            } else
                graph[i][j] = 0;
        }
    }
    for (int i = 0; i < maxNode; i++) {
        for (int j = 0; j < maxNode; j++) {
            graph[j][i] = graph[i][j];
        }
    }
    return graph;
}

Алгоритм :

void dijkstra(int **G, int n, int startnode) {
    printf("%d\n", startnode);
    int **cost = new int *[maxNode];
    int distance[maxNode], pred[maxNode];
    int visited[maxNode], count, mindistance, nextnode, i, j;
    for (i = 0; i < n; i++) {
        cost[i] = new int[maxNode];
        for (j = 0; j < n; j++)
            cost[i][j] = 0;
    }
    for (i = 0; i < n; i++)
        for (j = 0; j < n; j++)
            if (G[i][j] == 0)
                cost[i][j] = INFINITY;
            else
                cost[i][j] = G[i][j];
    for (i = 0; i < n; i++) {
        distance[i] = cost[startnode][i];
        pred[i] = startnode;
        visited[i] = 0;
    }
    distance[startnode] = 0;
    visited[startnode] = 1;
    count = 1;
    while (count < n - 1) {
        mindistance = INFINITY;
        for (i = 0; i < n; i++) {
            if (distance[i] < mindistance && !visited[i]) {
                mindistance = distance[i];
                nextnode = i;
            }
        }
        visited[nextnode] = 1;
        for (i = 0; i < n; i++) {
            if (!visited[i]) {
                if (mindistance + cost[nextnode][i] < distance[i]) {
                    distance[i] = mindistance + cost[nextnode][i];
                    pred[i] = nextnode;
                }
            }
        }
        count++;
    }
    delete[] cost;
    for (i = 0; i < n; i++)
        if (i != startnode) {
            j = i;
            do {
                j = pred[j];
            } while (j != startnode);
        }
}

И вот моя основная функция:

int main() {
    vector<int> graph = loadFile("..\\data\\newFile2.csv");
    int **graphConverted = formatGraph(graph);
    //printMatrix(graphConverted);
    clock_t begin = clock();
    for (int i = 0; i < maxNode; i++)
        dijkstra(graphConverted, maxNode, i);
    clock_t end = clock();
    double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
    printf("\nTime: %f", elapsed_secs);
    return 0;
}

Сначала данные загружаются в вектор, а затем преобразуются в матрицу смежности. Данные хранятся в форме:

src_node; dst_node; стоимость
1; 2; 3
1; 3; 30
1; 66; 20
et c.

Содержит набор данных из 1004 узлов и 25571 ребер.

Не могли бы вы предложить мне какое-нибудь решение, как это исправить?

1 Ответ

2 голосов
/ 05 января 2020

В dijkstra у вас есть динамическое c выделение памяти здесь:

int **cost = new int *[maxNode];

и здесь в al oop over i:

cost[i] = new int[maxNode];

У вас есть только один вызов delete[] в этой функции:

delete[] cost;

Таким образом, все распределения со второй строки new гарантированно будут утечки. Через некоторое время у вас не хватит памяти, в результате чего std::bad_alloc.

Вам необходимо сопоставить каждый new[] вызов с ровно одним delete[] вызовом.


Не использовать new / delete вообще. Вместо этого объявите все ваши массивы как std::vector, что позаботится об этом автоматически.

Также не используйте массивы переменной длины, такие как

int distance[maxNode], pred[maxNode];

Они нестандартные расширение компилятора. Сделайте также эти std::vector.

...