[C++] Sortowanie Shella

Forum dotyczące ogólnie pojętego programowania - algorytmów, struktur danych, narzędzi programistycznych, itp - głównie w kontekście komputerów PC.
ODPOWIEDZ
Awatar użytkownika
Luminofor
Użytkownik
Posty: 1373
Rejestracja: 27 lis 2007, 17:17
Lokalizacja: Polska

[C++] Sortowanie Shella

Post autor: Luminofor » 03 maja 2009, 23:56

Witam, napisałem program na sortowanie metoda Shella, czyli na dzielenie tablicy na mniejsze podtablice, przesortowaniu ich poprzez wybieranie (selection sort) i przy dążeniu z liczbą podtablic do 1, dążeniu do posortowania całej tablicy. Program liczy medianę i dominantę.
Będę wdzięczny za wszelkie uwagi i spostrzeżenia.

Kod: Zaznacz cały

// Sortowanie Shella

#include <iostream>

using namespace std;

int najmniejszy(int tablica[], int n, int start, int krok);
void shell(int tablica[], int n, int przedzial);
void wyniki_czastkowe(int tablica[], int n, int ktory_krok);
bool wprowadzanie_danych(int tablica[], int &n, int &ilosc_podciagow, int podciagi[]);
bool dystrybuanta(int tablica[], int n, int &dystry);
double mediana(int tablica[], int n);

int main()
{
	int tablica[100]={0},podciagi[100]={0},n,ilosc_podciagow,dystry;
	if(wprowadzanie_danych(tablica,n,ilosc_podciagow,podciagi)) //jesli wprowadzono wlasciwe dane
	{
		for(int k=0; k<ilosc_podciagow; k++) 
		{
			shell(tablica,n,podciagi[k]);  // to sortujemy
			wyniki_czastkowe(tablica,n,k); // i pokazujemy po kazdym kroku wyniki czastkowe
		}
		if(dystrybuanta(tablica,n,dystry)) cout << "\n  Dystrybuanta wynosi: " << dystry << "\n";  // jak jest dystrybuanta to pokazujemy
		else cout << "\n  Nie ma dystrybuanty!\n";   // a jak nie ma to nie :P
		cout << "  Mediana wynosi: " << mediana(tablica,n) << "\n\n";  // pokazanie mediany
	}
	return 0;
}

//***********************************************************
// poszukiwanie minimalnego elementu z danej podtablicy:
//***********************************************************
int najmniejszy(int tablica[], int n, int start, int krok)  
{
	int minimum=tablica[start], indeks_minimum=start;   // na poczatku zakladamy ze minimalny to pierwszy element podtablicy
	for(int j=start+krok; j<n; j=j+krok)      // szukanie kandydata na inne minimum w danej podtablicy
	{
		if(tablica[j]<minimum)
		{
			minimum=tablica[j];       // jest minimum
			indeks_minimum=j;         // i jego indeks ktory zwracamy do funkcji sortujacej
		}
	}
	return indeks_minimum;
}

//********************************************************
// wlasciwa funkcja sortujaca:
//********************************************************
void shell(int tablica[], int n, int przedzial)
{
	for(int k=0; k<przedzial; k++) //petla po ilosci podtablic w danym kroku
		{
		for(int j=k; j<n; j=j+przedzial) // petla w obrebie jednej podtablicy
		{
			int temp,indeks_najmniejszego=najmniejszy(tablica,n,j,przedzial);
			if(tablica[j]>tablica[indeks_najmniejszego]) // wykorzystujemy sortowanie przez wybieranie do sortowania podtablic
			{
				temp=tablica[j];                             //
				tablica[j]=tablica[indeks_najmniejszego];    // zamiana
				tablica[indeks_najmniejszego]=temp;          //
			}
		}
	}
}

//*****************************************************************
// pokazanie wynikow czastkowych po kazdym kroku:
//*****************************************************************
void wyniki_czastkowe(int tablica[], int n, int ktory_krok)
{
	if (!ktory_krok) cout << "\n";  //odstep przed pokazaniem pierwszego kroku
	cout << "  Krok nr " << ktory_krok+1 << ":   [";
	for(int i=0; i<n; i++)
	{
		cout << tablica[i];
		if(i<n-1) cout << ", ";  // brak przecinka na koncu
	}
	cout << "]\n";
}

//*************************************************************
// funkcja do wprowadzania danych:
//*************************************************************
bool wprowadzanie_danych(int tablica[], int &n, int &ilosc_podciagow, int podciagi[])
{
	cout << "Sortowanie Shella\n\nPodaj liczbe elementow: ";
	cin >> n;              // liczba elementow do posortowania
	if((n<1) || (n>100))   // zabezpieczenie przed przekroczeniem zakresu
	{
		cout << "\nZla liczba elementow!\n";
		return false;
	}
	for (int i=0; i<n; i++)  // wprowadzanie elementow do tablicy
	{
		if(!i) cout << "\n";
		cout << "Podaj element nr " << i+1 << ": ";
		cin >> tablica[i];
	}
	cout << "\nPodaj ilosc podciagow: ";
	cin >> ilosc_podciagow;   // ilosc podtablic (podciagow)
	for(int j=0; j<ilosc_podciagow; j++)
	{
		cout << "Podaj odstep podciagu " << j+1 << ": ";  // i ich odstepy (np. 5 - podtablica bedzie skladala sie z co piatego elementu)
		cin >> podciagi[j];
	}
	return true;
}

//***********************************************************
// wyznaczenie dystrybuanty: 
//***********************************************************
bool dystrybuanta(int tablica[], int n, int &dystry)  // zwracamy dystrybuante przez referencje
{
	int licznik=0, stary_licznik=0;
	for(int i=0; i<n; i++)   // przechodzimy po tablicy
	{
		if(tablica[i+1]==tablica[i])  // i patrzymy czy sie cos powtarza
		{
			licznik++;   // jesli tak to zwiekszamy licznik
			if(licznik>stary_licznik)  // ale patrzymy czy jest wiekszy od licznika z poprzedniego obiegu petli
			dystry=tablica[i];  // jesli tak, to mamy dystrybuante
		}
		else
		{
			licznik=0;  // albo nie :(
		}
		if((licznik) && licznik>stary_licznik) stary_licznik=licznik;  // ogolny licznik powtorzen elementow 
	}
	if(stary_licznik) return true;  // jak jest dystrybuanta to zwracamy true a jak nie ma to false
	else return false;
} 

//**************************************************
// wyliczenie mediany:
//**************************************************
double mediana(int tablica[], int n)
{
	if(!(n%2))  // jezeli n parzyste
		return (tablica[(n/2)-1]+tablica[n/2])/2.;
	return tablica[n/2];  // jezeli n nieparzyste
}

Awatar użytkownika
c4r0
Moderator
Posty: 2150
Rejestracja: 13 kwie 2004, 19:56
Lokalizacja: z lasu
Kontakt:

Post autor: c4r0 » 04 maja 2009, 15:34

Dlaczego piszesz takie dziwne programy zamiast czegoś co Ci się przyda?

Awatar użytkownika
Luminofor
Użytkownik
Posty: 1373
Rejestracja: 27 lis 2007, 17:17
Lokalizacja: Polska

Post autor: Luminofor » 04 maja 2009, 16:18

c4r0, nie rozumiem. Takie rzeczy przerabiamy na uczelni. Piszę, żeby nabrać wprawy.

Awatar użytkownika
c4r0
Moderator
Posty: 2150
Rejestracja: 13 kwie 2004, 19:56
Lokalizacja: z lasu
Kontakt:

Post autor: c4r0 » 04 maja 2009, 17:25

Aha, no chyba że to na zaliczenie. Myślałem że tak po prostu piszesz sam dla siebie w imię nauki. A wracając do tematu:
double mediana(int tablica[], int n)
{
if(!(n%2)) // jezeli n parzyste
return (tablica[(n/2)-1]+tablica[n/2])/2.;
return tablica[n/2]; // jezeli n nieparzyste
}
Coś jest nie tak w miejscu zaznaczonym na czerwono. Poza tym, nie ma sensu robić tej funkcji, zwłaszcza że jest wywoływana tylko w jednym miejscu kodu. Można napisać tak:

Kod: Zaznacz cały

cout << "  Mediana wynosi: " << (n%2)?(tablica[(n/2)-1]+tablica[n/2]):tablica[n/2]<< "\n\n";  // pokazanie mediany 

Awatar użytkownika
Luminofor
Użytkownik
Posty: 1373
Rejestracja: 27 lis 2007, 17:17
Lokalizacja: Polska

Post autor: Luminofor » 04 maja 2009, 17:29

To miejsce na czerwono co zaznaczyłeś, to niejawne rzutowanie z int na double, to było celowe. :)
Powiedzmy mamy taką posortowaną tablicę: 1 2 3 4, no to mediana = (2+3)/2=2, a (2+3)/2. = 2.5

Co do tego, ze można nie było robić funkcji odpowiem: chciałem uczynić swój program bardziej uniwersalnym, stąd takie rozbicie na funkcje. Gdybym chciał użyć teraz mediany w innym programie, to kopiuję tylko całą funkcję, a nie kombinuję z kodem.

ODPOWIEDZ