C++ generowanie grafu spójnego (przeszukiwania w g

Potrzebujesz pomocy z C, C++, perl, python, itp.
delpierog
Posty: 24
Rejestracja: 10 lutego 2011, 21:33

C++ generowanie grafu spójnego (przeszukiwania w głąb DFS) Segmentation fault

Post autor: delpierog »

Witajcie
Mam mały problem z generowaniem grafu spójnego dla zadanej wartości liczby wierzchołków. Graf potrzebny jest mi do badania czasu potrzebnego do wyznaczania najmniejszego drzewa spinającego algorytmami Kruskala i Prima. Idea programu jest taka aby wygenerować graf spójny generuje losowy graf o losowym wypełnieniu po czym sprawdzam go algorytmem dfs jeśli wszystkie wierzchołki zostaną odwiedzone graf jest spójny, jeśli zaś zostanie jakikolwiek wierzchołek nieodwiedzony generujemy graf od początku po czym wykonujemy jeszcze raz algorytm dfs. Program wydaje mi się że działa prawidłowo dla wierzchołków z zakresu 4-15 przy liczbie wierzchołków powyżej 15 wysypuje mi błąd Segmentation fault.

Kod: Zaznacz cały

#include <iostream>
#include <stdlib.h>
#include <vector>       //STL
#include <stack>        //STL

using namespace std;

void dfs(int wierzcholek,int Odwiedzony[],int liczba_wierzcholkow);
int przegladanie_w_glab(int liczba_wierzcholkow, int **tablica_lokalna);
int nastepnik_dfs(int wierzcholek,int **graf, int Odwiedzony[], int liczba_wierzcholkow);
void wyswietl_graf_spojny_dwa(int liczba_wierzcholkow, int **tablica_lokalna);
int generuj_graf_spojny_dwa(int liczba_wierzcholkow);
int **tablica_globalna;
int proba=1,liczba_wierzcholkow;

stack< int,vector<int> > stos;

int main()
{
cout <<"liczba wieczcholkow: ";
cin >> liczba_wierzcholkow;
generuj_graf_spojny_dwa(liczba_wierzcholkow);
przegladanie_w_glab(liczba_wierzcholkow, tablica_globalna);

return 0;
}

//Jeśli procedura wywołana dla pierwszego wierzchołka "dotrze" do wszystkich wierzchołków grafu to graf jest spójny.

int przegladanie_w_glab(int liczba_wierzcholkow, int **tablica_lokalna)
{

    int Odwiedzony[liczba_wierzcholkow];  //tablica w której zapisujemy odwiedzone wierzchołki zaznaczamy je "1"

    //zerowanie tablizy odwiedzonych wierzchołków
    for (int i=0; i<liczba_wierzcholkow; i++) Odwiedzony[i]=0;

    // Algoryt przeszukiwanie w głąb DFS
    dfs(0,Odwiedzony,liczba_wierzcholkow);

    //  jeśli suma wszystkich komórek Odwiedzone da nam liczbę wierzchołków to graf jest spójny
    int spojnosc=0;
    for(int i=0; i<liczba_wierzcholkow; i++)
    {
        spojnosc=spojnosc+Odwiedzony[i];
    }
    if(spojnosc==liczba_wierzcholkow)
    {
        cout << endl << "Wygenerowany graf jest grafem SPOJNYM (sprawdzono algorytmem DFS)"
              <<endl << "Wygenerowano za podejściem: "<<proba<<endl;
    }
    else
    {
        proba++;
        generuj_graf_spojny_dwa(liczba_wierzcholkow);
        przegladanie_w_glab(liczba_wierzcholkow,tablica_globalna);
    }
return 0;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//Funkcja zwraca OSTATNI nieodwiedzony nastepnik wierzcholka
int nastepnik_dfs(int wierzcholek,int **graf, int Odwiedzony[], int liczba_wierzcholkow)
{
    for (int i=liczba_wierzcholkow-1; i>0; i--)
    {[B]
        if ( (graf[i][wierzcholek] != 0) && (Odwiedzony[i]==0) )[/B]
        {
            Odwiedzony[i]=1;
            return(i);
        }
    }

//Wierzcholek nie ma juz nastepnikow do odwiedzenia
return(-1);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void dfs(int wierzcholek,int Odwiedzony[],int liczba_wierzcholkow)
{
    int u,nastepny;
    Odwiedzony[wierzcholek]=1;
    nastepny=nastepnik_dfs(wierzcholek,tablica_globalna,Odwiedzony,liczba_wierzcholkow);
    while (nastepny!=-1)
    {
        stos.push(nastepny);
        nastepny=nastepnik_dfs(wierzcholek,tablica_globalna,Odwiedzony,liczba_wierzcholkow);
    }

    if (!stos.empty())
    {
        u=stos.top();
        stos.pop();
        dfs(u,Odwiedzony,liczba_wierzcholkow);
    }
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int generuj_graf_spojny_dwa(int liczba_wierzcholkow)
{
    int krawedzie,procent,wygenerowane_krawedzie=0,licznik=1;

    //tworzy dynamiczną dwuwymirową tablicę o rozmiarach n x n
    int **tablica_lokalna = new int*[liczba_wierzcholkow];          //szerokość
    for (int x=0; x<liczba_wierzcholkow; x++)
    {
        tablica_lokalna[x] = new int[liczba_wierzcholkow];          //wysokość
    }


    //zerowanie tablicy
    for(int i=0; i<liczba_wierzcholkow; i++)
    {
        for(int j=0; j<=i; j++)
        {
            tablica_lokalna[i][j]=tablica_lokalna[j][i]=0;
        }
    }

    //wypełnia losowymi wartościami tablicę w miejscu (i,i) wsyawiamy zera bo krawędź nie istnieje
    //nie ma pętli wychodzących z ptk(i) i wracających do ptk(i) oraz puknty (a,b) i (b,a) mają taką samę wagę
    srand((unsigned)time(NULL));
    for(int i=0; i<liczba_wierzcholkow; i++)
    {
            for(int j=0; j<=i; j++)
            {
                if(j==i) tablica_lokalna[i][j]=0;
                else
                {
                    tablica_lokalna[i][j] = tablica_lokalna[j][i] = rand() % 4;
                    licznik++;
                }
            }
    }

    //liczymy wypełnienie
    for(int i=0; i<liczba_wierzcholkow; i++)
    {
        for(int j=0; j<=i; j++)
        {
            if(tablica_lokalna[i][j]!=0) wygenerowane_krawedzie++;

        }
    }
    krawedzie=liczba_wierzcholkow*(liczba_wierzcholkow-1)*0.5;
    procent=(wygenerowane_krawedzie*100/krawedzie);

    if(procent==100) generuj_graf_spojny_dwa(liczba_wierzcholkow);

    cout << endl << "Wypełenienie wygenerowanego grafu to: "<<procent<<"%"<<endl<<endl;
    tablica_globalna=tablica_lokalna;
    //wyświatlamy tablicę
    wyswietl_graf_spojny_dwa(liczba_wierzcholkow,tablica_globalna);

    //usuwa tablicę dwuwymiarową
    for(int x=0; x<liczba_wierzcholkow; x++) delete [] tablica_lokalna[x];
    delete []tablica_lokalna;

return 0;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void wyswietl_graf_spojny_dwa(int liczba_wierzcholkow, int **tablica)
{
    for(int i=0; i<liczba_wierzcholkow; i++)
    {
    cout <<"\t\t";
            for(int j=0; j<liczba_wierzcholkow; j++)
            {
            cout << tablica[i][j]<<" ";
            }

    cout << endl;
    }
}

Przy debugowaniu przekraczam pamięć w linii 66 (w kodzie wyżej pogrubiona). Czy mógłby mi ktoś pomóc znaleźć błąd w kodzie bądź nakierować dlaczego powyżej wartości 15 program zaczyna sypać błędy ? Potrzebuję aby graf był generowany w przybliżeniu do 1000 wierzchołków.
Czy jeśli ta implementacja jest do niczego można ten program napisać w jakiś prosty/lepszy sposób ?
Czocher
Beginner
Posty: 140
Rejestracja: 26 maja 2007, 23:19

Post autor: Czocher »

Kod: Zaznacz cały

liczba wieczcholkow: 1
==2708== 
==2708== Process terminating with default action of signal 8 (SIGFPE)
==2708==  Integer divide by zero at address 0x403F77EDD
==2708==    at 0x401377: generuj_graf_spojny_dwa(int) (test.cpp:149)
==2708==    by 0x400DFA: main (test.cpp:22)
Ponadto:

Kod: Zaznacz cały

liczba wieczcholkow: 15
==2741== Invalid read of size 8
==2741==    at 0x400FCC: nastepnik_dfs(int, int**, int*, int) (test.cpp:68)
==2741==    by 0x401074: dfs(int, int*, int) (test.cpp:85)
==2741==    by 0x400EBF: przegladanie_w_glab(int, int**) (test.cpp:39)
==2741==    by 0x400E11: main (test.cpp:23)
==2741==  Address 0x59fb0b0 is 112 bytes inside a block of size 120 free'd
==2741==    at 0x4C27EBC: operator delete[](void*) (vg_replace_malloc.c:515)
==2741==    by 0x401463: generuj_graf_spojny_dwa(int) (test.cpp:160)
==2741==    by 0x400DFA: main (test.cpp:22)
==2741== 
==2741== Invalid read of size 4
==2741==    at 0x400FDC: nastepnik_dfs(int, int**, int*, int) (test.cpp:68)
==2741==    by 0x401074: dfs(int, int*, int) (test.cpp:85)
==2741==    by 0x400EBF: przegladanie_w_glab(int, int**) (test.cpp:39)
==2741==    by 0x400E11: main (test.cpp:23)
==2741==  Address 0x59fb800 is 0 bytes inside a block of size 60 free'd
==2741==    at 0x4C27EBC: operator delete[](void*) (vg_replace_malloc.c:515)
==2741==    by 0x40143F: generuj_graf_spojny_dwa(int) (test.cpp:159)
==2741==    by 0x400DFA: main (test.cpp:22)
Polecam debugger valgrind.
mariaczi
Member
Posty: 1343
Rejestracja: 08 lutego 2008, 12:58
Lokalizacja: localhost@śląskie

Post autor: mariaczi »

Wykonujesz operacje na wskaźniku tablica_globalna (tablicy) dla którego nie masz rezerwowanego miejsca. Przeanalizuj dokładnie fragmenty gdzie masz przypisania, przepisania tablic (wskaźników).
Awatar użytkownika
Rafal_F
Moderator
Posty: 2350
Rejestracja: 29 sierpnia 2008, 16:45

Post autor: Rafal_F »

Generalnie w kodzie jest ogromny chaos. Z jednej strony masz zmienne globalne, ale i tak wszystkie potrzebne zmienne przekazujesz do funkcji jako parametry podczas wywołania. Zrezygnuj ze zmiennych globalny, są niepotrzebne. Do tego ta sama zmienna w różnych funkcjach nosi różne nazwy, to znacznie utrudnia analizę kodu.
delpierog
Posty: 24
Rejestracja: 10 lutego 2011, 21:33

Post autor: delpierog »

Dziękuję za zainteresowanie. Chyba jednak ten kod najrozsądniej będzie porządnie zreorganizować ale i tak bardzo dziękuję wszystkim za pomoc.
ODPOWIEDZ