Program nie działa poprawnie (zliczanie inwersji)

1

Moim problemem jest to że zrobiłem kod który działą dla danych wejsciowych zapisanych w pliku wejscie.txt, i robi to poprawnie.
Niestety kiedy tworzę własnych zestaw danych, program nie wypisuje prawidłowych wyników.
Podejrzewam, że jest to powiązane z problemem wczytywania z pliku. Wydaje mi się że nie jest to problem liczenia inwersji gdyż jak dane z wejscie2.txt dam do pliku wejscie.txt to program zadziała poprawnie.
Spedziłem kilka godzin nad debuggerem bez efektu. Wiem, że czasem wystarczy rzut oka kogoś innego, kto od razu znajdzie błąd dlatego bardzo proszę o pomoc.

EDIT:
Wszystko psuje się przy otwieraniu własnych generacji danych, program wykonuje się najpierw dla wejście.txt i wyświetla poprawna ilość inwersji, problem zaczyna się gdy chce wygenerować plik z danymi, sam plik generuje się poprawnie i otwiera się poprawnie, niestety wyświetla że liczba inwersji jest 0. Nie jest to problem zaliczania inwersji bo gdy włączę program jeszcze raz i zamienię żeby najpierw czytało z pliku wejscie2.txt to inwersje zostaną dobrze policzone.

Kod główny programu:


#include "metodyfunkcje.h"

//***************************************************************************************
int merge(long long int array[], int p, int q, int r, long long int lowhalf[], long long int highhalf[])
{
	int k = p;
	int i;
	int j;
	int count = 0;
	for (int i = 0; k <= q; i++ , k++)
	{
		lowhalf[i] = array[k];
	}
	for (int i = 0; k <= r; i++ , k++)
	{
		highhalf[i] = array[k];
	}

	k = p;
	i = 0;
	j = 0;

	while (i <= (q - p) && j <= r - (q + 1))
	{
		if (lowhalf[i] <= highhalf[j])
		{
			array[k] = lowhalf[i];
			i++;
		}
		else
		{
			array[k] = highhalf[j];
			j++;
			count += (q + j - k);
		}

		k++;
	}

	while (i < lowhalflength(p, q))
	{
		array[k] = lowhalf[i];
		k++;
		i++;
	}

	while (j < highhalflength(q, r))
	{
		array[k] = highhalf[j];
		k++;
		j++;
	}


	return count;
}

//***************************************************************************************
/*
Dzieli problem na podproblemy i wywoluje dla pojedynczego elementu funkcje merge
p-poczatek tablicy
r-koniec tablicy
q-srodek tablicy
*/
int mergeSort(long long int array[], int p, int r)
{
	long long int q = ((p + r) / 2);
	long long int* lowhalf = cre_dyn_arr<long long int>((lowhalflength(p, q)));
	long long int* highhalf = cre_dyn_arr<long long int>((highhalflength(q, r)));

	int count = 0;
	if (p < r)
	{
		q = ((p + r) / 2);
		count = mergeSort(array, p, q);
		count += mergeSort(array, q + 1, r);
		count += merge(array, p, q, r, lowhalf, highhalf);
	}
	delete[] lowhalf;
	delete[] highhalf;

	return count;
}

//***************************************************************************************
int main()
{
	int amount_of_collections;
	ofstream Filetowrite;
	ifstream Filetoread;

	open_file(Filetoread, "wejscie.txt");
	create_file(Filetowrite, "wyjscie.txt");

	Filetoread >> amount_of_collections;

	main_algorithm(amount_of_collections, Filetowrite, Filetoread);


	cout << "Wywolanie programu dla losowo wygenerowanych liczb\n";

	cout << "Przygotowuje liczby pseudo-losowe, prosze o podanie ile ma byc kolekcji:\n";
	cin >> amount_of_collections;

	random_num_tofile(Filetowrite, amount_of_collections);


	open_file(Filetoread, "wejscie2.txt");
	create_file(Filetowrite, "wyjscie2.txt");
	main_algorithm(amount_of_collections, Filetowrite, Filetoread);

	getchar();
	getchar();

	return 0;
}

 

Kod z pliku "metodyfunkcje.h":

 
#include <iostream>
#include <fstream>
#include <random>
using namespace std;

extern int mergeSort(long long int array[], int p, int r);

//********************************************************************************
inline int lowhalflength(int p, int q)
{
	return (q - p + 1);
}

inline int highhalflength(int q, int r)
{
	return (r - q);
}

//********************************************************************************
template <class type>
type* cre_dyn_arr(long long int n)
{
	type* pointer = nullptr;
	try
	{
		pointer = new type[n];
	}
	catch (bad_alloc)
	{
		cerr << "\nNiestety nie ma wolnej pamieci na zarezerwowanie  " << n << " elementowej tablicy!";
		getchar();
		getchar();
		exit(0);
	}


	return pointer;
}

//********************************************************************************
void main_algorithm(int amount_of_collections, ofstream& Filetowrite, ifstream& Filetoread)
{
	long long int temp;
	int amountofnumbers = 0;
	long long int* wsk;
	long long int* tempwsk;
	int tempamount;
	int z = 0;
	for (int i = 0; i < amount_of_collections; i++)
	{
		Filetoread >> amountofnumbers;
		wsk = cre_dyn_arr<long long int>(amountofnumbers);
		tempamount = amountofnumbers;
		tempwsk = wsk;
		z = 0;
		while (amountofnumbers > 0)
		{
			Filetoread >> temp;
			wsk[z] = temp;
			amountofnumbers--;
			z++;
		}


		cout << mergeSort(wsk, 0, tempamount - 1) << "\n";

		delete[] wsk;
	}

	Filetoread.close();
	Filetowrite.close();
	
	cout << "Program zostal wykonany poprawnie\n";
}

//********************************************************************************
void create_file(ofstream& File, char* name = "")
{
	if (name == "")
	{
		cout << "Prosze o podanie nazwy pliku z rozszerzeniem, jaki mam stworzyc do wypisywania wynikow\n";
		char tab[20] = {'\0'};
		bool type = false;
		cin >> tab;

		for (int i = 0; i < 20; i++)
		{
			if (tab[i] == '.') type = true;
		}
		if (!type)
		{
			cerr << "Nie podales rozszerzenia, koncze program\n";
			getchar();
			exit(0);
		}
		File.open(tab);
	}
	else
	{
		File.open(name);
		if (!File)
		{
			cerr << "Nie moglem stworzyc pliku\n";
			getchar();
			exit(0);
		}
	}
}

//********************************************************************************
void open_file(ifstream& File, char* name = "")
{
	char tab[20] = {'\0'};
	int i = 2;
	int a = 0;
	if (name == "")
	{
		do
		{
			cerr << "Wprowadz nazwe pliku do odczytania, z rozszerzeniem nie uzywajac bialych znakow (limit 20 znakow)\n";
			cin >> tab;

			File.open(tab);

			if (!File)
			{
				cerr << "Plik otwarty niepoprawnie\n";
			}
			else break;

			i--;
		}
		while (i != 0);
		if (!i)
		{
			cerr << "Wykorzystales swoj limit prob!\n";
			getchar();
			exit(0);
		}
	}

	else
	{
		File.open(name);
		if (!File)
		{
			cerr << "Plik otwarty niepoprawnie, koncze program\n";
			getchar();
			exit(0);
		}
	}
	cout << "Plik zostal otworzony poprawnie\n";
}

//********************************************************************************

void random_num_tofile(ofstream& File, long long int amountofcollections)
{
	random_device rd;
	mt19937_64 gen(rd());
	long long int max = 281474976710656;
	long long int min = -281474976710655;
	uniform_int_distribution<long long int> dis(2, 10);
	int amountofnumbers;


	create_file(File, "wejscie2.txt");
	File << amountofcollections << "\n";

	while (amountofcollections > 0)
	{
		cout << "Prosze o podanie ile ma byc liczb w kolekcji\n";
		cin >> amountofnumbers;
		File << amountofnumbers << "\n";
		while (amountofnumbers > 0)
		{
			File << dis(rd) << " ";
			amountofnumbers--;
		}
		File.seekp(-1, ios::end);
		amountofcollections--;
		if (amountofcollections > 0) File << "\n";
	}

	File.close();
	cout << "Wypisywanie liczb do pliku zakonczylo sie sukcesem\n";
}

0

Strzelam,
Pliki wyjściowe są puste?
w void random_num_tofile(ofstream& File, long long int amountofcollections)
masz File << dis(rd) << " ";
może aby zobaczyć czy działa to poprawnie zmień na
cout << dis(rd) << " ";
powinieneś napisać co dokładnie nie działa jak napisał fasadin.

1
  1. Nie rozumiesz zasady inkrementacji http://4programmers.net/Forum/1101404
  2. Nie używaj char* name; bo to prowadzi do błędów, np: char* a,b; - zmienna a jest wskaźnikiem natomiast b nie jest. Używaj char *a,b; tak przynajmniej widać że b jest innego typu niż a.
  3. char* name = "" - w C++ nie możesz literały konwertować do char*
  4. name == "" - porównujesz adresy nawet nie masz gwarancji że jeden "" będzie równy drugiemu "" bo kompilator ma prawo tego nie zoptymalizować ... @Endrju - czy nie chrzanię?
  5. Jeżeli potrzebujesz getchar(); do zatrzymania ekranu to może zmień IDE na jakieś z tego tysiąclecia, te z tego tysiąclecia mają opcję zatrzymania ekranu.
  6. Policz ile razy występuję ci taki fragment kodu:
      if(!File)
        {
         cerr << "Nie moglem stworzyc pliku\n";
         getchar();
         exit(0);
        }

może zrób z tego funkcję:

void fatal(bool bad,const char *msg) { if(bad) exit(!(cerr<<msg<<endl)); }
//użycię:
fatal(!File,"Nie moglem stworzyć pliku");
  1. W każdym miejscu czytającym cokolwiek ze strumienia podanego jako parametr na początku funkcji daj: fatal(!File,"Spodziewano się poprawnie otwartego pliku"); a zobaczysz na czym polega błąd
  2. Rozwiązaniem problemu jest File.clear(); przed ponownym otwarciem.
  3. cin >> tab; - bardzo niebiezpiecznie przynajmniej użyj: cin>>setw(19)>>tab; lub: cin>>setw(sizeof(tab)-1)>>tab;
  4. Zamiast: for (int i = 0; i < 20; i++) { if (tab[i] == '.') type = true; } wystarczy: type=strchr(tab,'.'); Ale @mwl4, słusznie radzi (w komentarzu niestety) użyć string oraz string::find
0

void fatal(bool bad,const char *msg) { if(bad) exit(!(cerr<<msg<<endl)); }
Jak to już jest fatal, to chyba nie bad? Chyba, że są złe i dobre fatale :-) Rozumiem intencję - przeniesienie często sprawdzanego warunku do środka funkcji, ale wtedy nazwa funkcji powinna być inna, np. write_message_and_halt_if albo write_message_and_halt_if_true.

BTW (to już do autora wątku) słabo wygląda notacja php stosowana w C++.

0

Dziękuje bardzo wszystkim za pomoc i konstruktywną krytykę, zgadzam się z przedmówcami, że niektóre części mojego kodu są nie za bardzo bezpieczne, postaram się poprawić na przyszłość, a co do preinkrementacji, to moim zdaniem niezłą wojenkę zrobiliście na tym forum.

A co do błędu to zapomniałem tylko napisać

open_file(Filetoread, "wejscie2.txt");
create_file(Filetowrite, "wyjscie2.txt");
Filetoread >> amount_of_collections; // **tej linijki**
main_algorithm(amount_of_collections, Filetowrite, Filetoread);

Reszta działa dobrze :)

0

Przed "tą linijką" daj: if(!Filetoread) cerr<<"Czytaj uważniej co ci piszą\n";

1 użytkowników online, w tym zalogowanych: 0, gości: 1