Создание случайного неориентированного графа в C++

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

Я попытался написать код, который будет создавать граф на основе входных данных - количества вершин и общего количества ребер (максимальное количество ребер в неориентированном графе равно n (n-1)/2).

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

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <list>
#include <set>

#define MAX 1000
#define MIN 1

class Vertex
{
public:
    int Number;
    int Distance;
    Vertex(void);
    Vertex(int, int);
    ~Vertex(void);
};

Vertex::Vertex(void)
{
    Number = 0;
    Distance = 0;
}

Vertex::Vertex(int C, int D)
{
    Number = C;
    Distance = D;
}

Vertex::~Vertex(void)
{
}


int main()
{
    int VertexNumber, EdgeNumber;

    while(scanf("%d %d", &VertexNumber, &EdgeNumber) > 0)
    {
        int EdgesFromVertex = (EdgeNumber/VertexNumber);

        std::list<Vertex>* Graph = new std::list<Vertex> [VertexNumber];

        srand(time(NULL));

        int Distance, Neighbour;
        bool Exist, First;

        std::set<std::pair<int, int>> Added;

        for(int i = 0; i < VertexNumber; i++)
        {
            for(int j = 0; j < EdgesFromVertex; j++)
            {
                First = true;
                Exist = true;

                while(First || Exist)
                {
                    Neighbour = rand() % (VertexNumber - 1) + 0;

                    if(!Added.count(std::pair<int, int>(i, Neighbour)))
                    {
                        Added.insert(std::pair<int, int>(i, Neighbour));
                        Exist = false;
                    }
                    First = false;
                }
            }

            First = true;
            std::set<std::pair<int, int>>::iterator next = Added.begin();

            for(std::set<std::pair<int, int>>::iterator it = Added.begin(); it != Added.end();)
            {
                if(!First)
                    Added.erase(next);

                Distance = rand() % MAX + MIN;

                Graph[it->first].push_back(Vertex(it->second, Distance));
                Graph[it->second].push_back(Vertex(it->first, Distance));

                std::set<std::pair<int, int>>::iterator next = it;
                First = false;
            }
        }

        // Dijkstra's implementation
    }

    return 0;
}

Я получаю сообщение об ошибке:

установить итератор, не допускающий разыменования» при попытке создать график из заданных данных.

Я знаю, что это как-то связано со стиранием элементов набора на лету, однако мне нужно стереть их как можно скорее, чтобы уменьшить использование памяти.

Может быть, есть лучший способ создать неориентированный граф? Мой довольно сырой, но это лучшее, что я придумал. Я думал о создании ориентированного графа, который является более простой задачей, но он не гарантирует, что каждые две вершины будут связаны.

Буду признателен за любые советы и решения!


person Community    schedule 08.06.2013    source источник
comment
Вы можете создать матрицу N на N, заполненную 0, и случайным образом установить 1 тыс. ячеек в этой матрице. Перевод из матричного представления в векторное выполняется прямо.   -  person Piotr Jaszkowski    schedule 08.06.2013
comment
@piotr в матрице неориентированного графа должен быть симметричным   -  person blue    schedule 08.06.2013
comment
Я взял основную идею использования матрицы и добавил некоторые улучшения. Пока могу сказать, что результаты довольно кредитоспособны.   -  person    schedule 08.06.2013


Ответы (2)


У Пиотри была в основном та же идея, что и у меня, но он остановился на шаг.

Прочитайте только половину матрицы и игнорируйте диагональ для записи значений. Если вы хотите, чтобы узел всегда имел ребро, добавьте его по диагонали. Если вы не хотите, чтобы узел всегда имел ребро для себя, оставьте его равным нулю.

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

person Brian Stinar    schedule 09.06.2013

Посмотрите на описание std::set::erase :

Действительность итератора

  • Итераторы, указатели и ссылки, ссылающиеся на элементы, удаленные функцией, становятся недействительными.
  • Все остальные итераторы, указатели и ссылки сохраняют свою действительность.

В вашем коде, если next равно it, и вы стираете элемент std::set на next, вы не можете использовать it. В этом случае вы должны (как минимум) изменить it и только после этого продолжать использовать it.

person Boris    schedule 08.06.2013