[C++]Metoda Laplace'a

Adamant4
Użytkownik
Użytkownik
Posty: 6
Rejestracja: 5 wrz 2012, o 13:59
Płeć: Mężczyzna
Lokalizacja: Grodzisk Mazowiecki

[C++]Metoda Laplace'a

Post autor: Adamant4 »

Próbuję napisać program co wczytuje dane(macierz) z pliku i liczy jego wyznacznik. Szukam błędów i nie mogę znaleźć. Może ktoś świeżym spojrzeniem coś zauważy :)

Kod: Zaznacz cały

#include <iostream>
#include <math.h>
#include <fstream>

using namespace std;

int **zbuduj_macierz(int rozmiar){
		// Dynamiczna alokacja pamieci
		int **macierz = new int*[rozmiar];
		for(int i=0;i < rozmiar;i++){
			macierz[i] = new int[rozmiar]; 
		}
	return macierz;
}
//Redukuje macierz poprzez wykreslenie nr_wiersza i nr_kolumny do wielkosci rozmiar-1
//Indeksy liczymy od 0 !
int **redukuj_macierz(int **macierz_pierwotna,int rozmiar,int nr_wiersza,int nr_kolumny){
	int **macierz_zredukowana = zbuduj_macierz(rozmiar-1);
	//i,k - beda przesuwac po macierzy pierwotnej
	//j,l - po macierzy zredukowanej
	for(int i=0,j=0;i<rozmiar;i++){
		if(i==nr_wiersza)continue;
		for(int k=0,l=0;k<rozmiar;k++){
			if(k==nr_kolumny)continue;
			else{
				macierz_zredukowana[j][l] = macierz_pierwotna[i][k];
				l++;
			}
		}
		j++;
	}
	return macierz_zredukowana;
}

void wczytaj_graf(int **tab){
	FILE * plik;
	int rozmiar=0;
	plik = fopen("graf.txt","r");
	if(plik != NULL){
		//Wczytuje macierz. Pomijajac pierwsza liczbe mowiaca o liczbie krawedzi
		fscanf(plik,"%d",&rozmiar);
		for(int i=0;i<rozmiar;i++){
			for(int j=0;j < rozmiar;j++){
				fscanf(plik,"%d",&tab[i][j]);
			}
		}
	}else
		printf("Plik graf.txt nie istnieje");
		
	printf("Ilosc krawedzi: %d\n\n",rozmiar); 
	fclose(plik);
}
int wyznacznik(int **macierz, int rozmiar){
	int det = 0,max = 0,nr_wiersza,licznik = 0;
	//Dla macierzy stopnia 1x1 badz 2x2 wyznacznik obliczany z definicji
	if(rozmiar == 1) return macierz[0][0];
	if(rozmiar == 2) return (macierz[0][0]*macierz[1][1] - macierz[0][1]*macierz[1][0]);
	//W innym przypadku rozwiniecie LaPlace'a
	int **zredukowana_macierz;
	//Szukam wiersza w ktorym jest najwiecej zer
	for(int i=0;i < rozmiar;i++){
		licznik = 0;
		for(int j=0;j < rozmiar;j++){
			if(macierz[i][j] == 0)licznik++;
		}
		if(licznik > max){
			max = licznik;
			nr_wiersza = i;
		} 
	}
	//Wybrany wiersz bedzie uzyty do wykreslania macierzy
	//Teraz wykreslam odpowiednio macierz, licze wyznacznik dopelnienia i dodaje do wyniku
	for(int i=0;i<rozmiar;i++){
		zredukowana_macierz = redukuj_macierz(macierz,rozmiar,nr_wiersza,i);
		// >:*
		det += macierz[nr_wiersza][i]*pow((-1),(nr_wiersza+i))*(wyznacznik(zredukowana_macierz,rozmiar-1));
	}
	return det;
}

int main(){
		FILE * plik;
		plik = fopen("graf.txt","r");
		int rozmiar=0;
		int **tab;
		if(plik == NULL) return 0;
		//Wczytuje ilosc krawedzi
		fscanf(plik,"%d",&rozmiar);
		//Tworze macierz
		tab = zbuduj_macierz(rozmiar);
		//Wczytuje dane z pliku
		wczytaj_graf(tab);
		
		//Wypisuje zawartosc
		for(int i=0;i < rozmiar;i++){
			printf("%d.  ",i+1);
			for(int j=0;j<rozmiar;j++){
				printf("%d  ",tab[i][j]);
			}
			printf("\n");
		}
		
		cout <<"Wyznacznik macierzy wynosi: " << wyznacznik(tab,rozmiar) << endl;
		//Sprzątamy po sobie
		for(int i=0;i < rozmiar;i++){
			delete tab[i];
		}
		delete tab;
		fclose(plik);
}
Awatar użytkownika
Peter Zof
Użytkownik
Użytkownik
Posty: 585
Rejestracja: 30 cze 2012, o 16:07
Płeć: Mężczyzna
Lokalizacja: Warszawa (MIMUW) / Pułtusk
Podziękował: 88 razy
Pomógł: 66 razy

[C++]Metoda Laplace'a

Post autor: Peter Zof »

Ogólnie to trochę nieciekawie zwalniasz tą tablicę Są od tego odpowiednie operatory: new i delete.
Awatar użytkownika
MichalPWr
Użytkownik
Użytkownik
Posty: 1625
Rejestracja: 29 wrz 2010, o 15:55
Płeć: Mężczyzna
Lokalizacja: Leszno
Podziękował: 7 razy
Pomógł: 387 razy

[C++]Metoda Laplace'a

Post autor: MichalPWr »

Peter Zof, Nie tyle co nieciekawy, co nie dokładnie. Zwalnia tylko fragment zaalokowanej pamięci.
Adamant4, Niepotrzebnie dodajesz bibliotekę

Kod: Zaznacz cały

iostream
Zapodaj pliki testowe.

Zdecyduj się czy piszesz w C czy C++!
Adamant4
Użytkownik
Użytkownik
Posty: 6
Rejestracja: 5 wrz 2012, o 13:59
Płeć: Mężczyzna
Lokalizacja: Grodzisk Mazowiecki

[C++]Metoda Laplace'a

Post autor: Adamant4 »

C w pełni zawiera się w C++ więc nie widzę problemu.

Kod: Zaznacz cały

 for(int i=0;i < rozmiar;i++){
         delete tab[i];
      }
      delete tab;
Jest złym zwalnianiem pamięci? Powyższy program trochę przerobiłem i już działa.

Kod: Zaznacz cały

#include <iostream>
#include <math.h>
#include <fstream>

using namespace std;

int **zbuduj_macierz(int rozmiar){
		// Dynamiczna alokacja pamieci
		int **macierz = new int*[rozmiar];
		for(int i=0;i < rozmiar;i++){
			macierz[i] = new int[rozmiar]; 
		}
	return macierz;
}
//Redukuje macierz poprzez wykreslenie nr_wiersza i nr_kolumny do wielkosci rozmiar-1
//Indeksy liczymy od 0 !
int **redukuj_macierz(int **macierz_pierwotna,int rozmiar,int nr_wiersza,int nr_kolumny){
	int **macierz_zredukowana = zbuduj_macierz(rozmiar-1);
	//i,k - beda przesuwac po macierzy pierwotnej
	//j,l - po macierzy zredukowanej
	for(int i=0,j=0;i<rozmiar;i++){
		if(i==nr_wiersza)continue;
		for(int k=0,l=0;k<rozmiar;k++){
			if(k==nr_kolumny)continue;
			else{
				macierz_zredukowana[j][l] = macierz_pierwotna[i][k];
				l++;
			}
		}
		j++;
	}
	return macierz_zredukowana;
}

void wczytaj_graf(int **tab){
	FILE * plik;
	int rozmiar=0;
	plik = fopen("graf.txt","r");
	if(plik != NULL){
		//Wczytuje macierz.
		fscanf(plik,"%d",&rozmiar);
		for(int i=0;i<rozmiar;i++){
			for(int j=0;j < rozmiar;j++){
				fscanf(plik,"%d",&tab[i][j]);
			}
		}
	}else
		printf("Plik graf.txt nie istnieje");
		
	printf("Ilosc krawedzi: %d\n\n",rozmiar); 
	fclose(plik);
}
int wyznacznik(int **macierz, int rozmiar){
	int det = 0,max = 0,nr_wiersza=0,licznik = 0;
	//Dla macierzy stopnia 1x1 badz 2x2 wyznacznik obliczany z definicji
	if(rozmiar == 1) return macierz[0][0];
	if(rozmiar == 2) return (macierz[0][0]*macierz[1][1] - macierz[0][1]*macierz[1][0]);
	//W innym przypadku rozwiniecie LaPlace'a
	int **zredukowana_macierz;
	//Szukam wiersza w ktorym jest najwiecej zer
	for(int i=0;i < rozmiar;i++){
		licznik = 0;
		for(int j=0;j < rozmiar;j++){
			if(macierz[i][j] == 0)licznik++;
		}
		if(licznik > max){
			max = licznik;
			nr_wiersza = i;
		} 
	}
	//Wybrany wiersz bedzie uzyty do wykreslania macierzy
	//Teraz wykreslam odpowiednio macierz, licze wyznacznik dopelnienia i dodaje do wyniku
	for(int i=0;i<rozmiar;i++){
		zredukowana_macierz = redukuj_macierz(macierz,rozmiar,nr_wiersza,i);
		// >:*
		det += macierz[nr_wiersza][i]*(long double)pow((-1),(nr_wiersza+i))*(wyznacznik(zredukowana_macierz,rozmiar-1));
	}
	return det;
}

int main(){
		FILE * plik;
		plik = fopen("graf.txt","r");
		int rozmiar=0;
		int **tab,**red;
		if(plik == NULL) return 0;
		//Wczytuje ilosc krawedzi
		fscanf(plik,"%d",&rozmiar);
		//Tworze macierz
		tab = zbuduj_macierz(rozmiar);
		//Wczytuje dane z pliku
		wczytaj_graf(tab);
		red = redukuj_macierz(tab,rozmiar,0,0);
		//Wypisuje zawartosc
		for(int i=0;i < rozmiar;i++){
			printf("%d.  ",i+1);
			for(int j=0;j<rozmiar;j++){
				printf("%d  ",tab[i][j]);
			}
			printf("\n");
		}
		cout << endl << "Test redukowania macierzy(wiersz 1 i kolumna 1)" << endl << endl;
		for(int i=0;i < (rozmiar-1);i++){
			printf("%d.  ",i+1);
			for(int j=0;j < (rozmiar-1);j++){
				printf("%d  ",red[i][j]);
			}
			printf("\n");
		}
		
		cout <<"Wyznacznik macierzy wynosi: " << wyznacznik(tab,rozmiar) << endl;
		//Sprzątamy po sobie
		for(int i=0;i < rozmiar;i++){
			delete tab[i];
			delete red[i];
		}
		delete tab;
		delete red;
		fclose(plik);
}
-- 6 kwi 2013, o 01:28 --
Peter Zof pisze:Ogólnie to trochę nieciekawie zwalniasz tą tablicę :D Są od tego odpowiednie operatory: new i delete.
w dynamicznej alokacji używam new a do zwalniania pamięci delete więc chyba wszystko ok.
Awatar użytkownika
MichalPWr
Użytkownik
Użytkownik
Posty: 1625
Rejestracja: 29 wrz 2010, o 15:55
Płeć: Mężczyzna
Lokalizacja: Leszno
Podziękował: 7 razy
Pomógł: 387 razy

[C++]Metoda Laplace'a

Post autor: MichalPWr »

Adamant4, Nawet nie wiesz jak bardzo się mylisz
Jutro wieczorem przeglądnę sam program.
Adamant4
Użytkownik
Użytkownik
Posty: 6
Rejestracja: 5 wrz 2012, o 13:59
Płeć: Mężczyzna
Lokalizacja: Grodzisk Mazowiecki

[C++]Metoda Laplace'a

Post autor: Adamant4 »

C zawiera się w C++ a nie odwrotnie, i tu się nie mylę.
Afish
Moderator
Moderator
Posty: 2828
Rejestracja: 15 cze 2008, o 15:45
Płeć: Mężczyzna
Lokalizacja: Seattle, WA
Podziękował: 3 razy
Pomógł: 356 razy

[C++]Metoda Laplace'a

Post autor: Afish »

Ani C nie zawiera się w C++, ani C++ nie zawiera się w C. Dawniej była zachowana kompatybilność między nimi, obecnie już nie jest.
Adamant4
Użytkownik
Użytkownik
Posty: 6
Rejestracja: 5 wrz 2012, o 13:59
Płeć: Mężczyzna
Lokalizacja: Grodzisk Mazowiecki

[C++]Metoda Laplace'a

Post autor: Adamant4 »

Ten drugi kod, który wrzuciłem już działa ale jest jeden problem. Jak odpalam program kilka razy pod rząd to mniej więcej co 4-6 odpalenia po wyświetleniu wyniku program się zawiesza "program przestał działać" itp. Wydaje mi się, że jest to powodem niekompletnego zwalniania pamięci. Możecie mi pomóc jak w tej funkcji rekurencyjnej zrobić zwalnianie pamięci? Raczej ta część jest przyczyną
Awatar użytkownika
MichalPWr
Użytkownik
Użytkownik
Posty: 1625
Rejestracja: 29 wrz 2010, o 15:55
Płeć: Mężczyzna
Lokalizacja: Leszno
Podziękował: 7 razy
Pomógł: 387 razy

[C++]Metoda Laplace'a

Post autor: MichalPWr »

Pamięć zwalniasz tak

Kod: Zaznacz cały

delete []nazwa_tablicy;
Ser Cubus
Użytkownik
Użytkownik
Posty: 1406
Rejestracja: 6 maja 2012, o 22:46
Płeć: Mężczyzna
Lokalizacja: Polska
Podziękował: 107 razy
Pomógł: 145 razy

[C++]Metoda Laplace'a

Post autor: Ser Cubus »

Afish pisze:Ani C nie zawiera się w C++, ani C++ nie zawiera się w C. Dawniej była zachowana kompatybilność między nimi, obecnie już nie jest.
hmm? a mógłbyś podać przykład?
Afish
Moderator
Moderator
Posty: 2828
Rejestracja: 15 cze 2008, o 15:45
Płeć: Mężczyzna
Lokalizacja: Seattle, WA
Podziękował: 3 razy
Pomógł: 356 razy

[C++]Metoda Laplace'a

Post autor: Afish »

C++ - szablony. C - VLA, FAM. I przy okazji: C++11 nie jest już kompatybilny wstecznie (modyfikator export), ale to taki szczegół. C również nie jest kompatybilny wstecznie - część rzeczy z C99 zostały oznaczone jako opcjonalne w C11.
Awatar użytkownika
MichalPWr
Użytkownik
Użytkownik
Posty: 1625
Rejestracja: 29 wrz 2010, o 15:55
Płeć: Mężczyzna
Lokalizacja: Leszno
Podziękował: 7 razy
Pomógł: 387 razy

[C++]Metoda Laplace'a

Post autor: MichalPWr »

Przy okazji warto zwrócić uwagę na dużą różnicę pomiędzy unget() w C++(ISO 14882) a C++11, podczas czytania ze strumienia.
ODPOWIEDZ