[C]Problem z sortowanie struktur w tablicy metodą prostego wybierania




szmitek11.01.2009 02:38:53
#
Dołączył: 04.01.2009

Mam problem z sortowaniem:

#include <stdio.h> //printf, puts, scantf, fgets

include <ctype.h> //isalpha, toupper, tolower

include <string.h> //strcmp, strlen

define n 50

struct plant //deklaracja struktury { char name[31]; //nazwa rośliny char kind[31]; //rodzaj rośliny char origin[31]; //pochodzenie rośliny unsigned id; //numer rośliny }; struct plant table[n]; //deklaracja tablicy struktur int sortingByName, number; //deklaracja zmiennych liczbowych do określenia sortowania i liczby rośliny void Add(void); int GetText(char description[], char target[31], int cancelForSpace); void GetID(int i, int cancelForZero); void SortAndDisplay(void); void Change(int remove); int main(void) { int operation; puts("\nProgram służy do wprowadzania i sortowania roślin z ich rodzajami, pochodzeniem i pięciocyfrowym numerem."); //opis programu Add(); //dodaj nowe rośliny sortingByName = 0; //ustaw sortowanie według numerów SortAndDisplay(); //sortuj i wyświetl rośliny do { if (scanf("%i",&operation) == 0) //wybór operacji przez użytkownika { return 0; //zamknij program } fgets(afterTarget, 2, stdin); switch (operation) //operacja 1, 2, 3 lub 4 wybrana przez użytkownika { case 1: if (sortingByName == 0) { sortingByName = 1; //sortuj według nazw } else { sortingByName = 0; //sortuj według numerów } SortAndDisplay(); //sortuj i wyświetl osoby break; case 2: Add(); //dodaj nowe rośliny SortAndDisplay(); //sortuj i wyświetl rośliny break; (...) } } while (operation != 5); //operacja 5 wybrana przez użytkownika return 0; } (...) void SortAndDisplay(void) //sortuje i wyświetla rośliny { struct plant temp; //deklaracja tablicy tymczasowowej int h, i, j, x, k; //dekracja zmiennych pomocniczych dla pętli number = 0; for (h=0; h<n && table[h].id > 0; ++h) ///pętla do zliczania roślin { number++; } if (number != 0) { for (i=0; i<number-1; ++i) //sortowanie metodą prostego wybierania { x = i; temp = table [i]; for (j = i+1; j<number; ++j) { if (strcmp(table[j].origin, temp.origin) < 0 && ((sortingByName == 0 && table[j].id > temp.id) || (sortingByName == 1 && strcmp(table[j].name, temp.name) < 0))) { x = j; temp = table[j]; } table[x] = table [i]; table [i] = temp; } } if (sortingByName == 0) { printf("\nLISTA RO¦LIN\nSortowanie alfabetyczne według pochodzenia i malejąco według numerów\n\n%-33s %-33s %s\n\n", "Nazwa", "Rodzaj", "Numer"); //nagłowek tabeli dla sortowania według numeru rośliny wewnatrz działu } else { printf("\nLISTA RO¦LIN\nSortowanie alfabetyczne według pochodzenia i nazwy\n\n%-33s %-33s %s\n\n", "Nazwa", "Rodzaj", "Numer"); //nagłowek tabeli dla sortowania według nazwy rośliny według działow } printf("%s:\n%-33s %-33s %u\n", table[0].origin, table[0].name, table[0].kind, table[0].id); for (k=1; table[k].id>0 && k<n; k++) { if (strcmp(table[k].origin, table[k-1].origin)) { printf("\n%s:\n", table[k].origin); } printf("%-33s %-33s %u\n", table[k].name, table[k].kind, table[k].id); } } else { printf("\nBrak roślin"); } } ...

Sortowanie metodą prostego wybierania w funkcji SortAndDisplay nie działa prawidłowo. Posortuje według "origin", gdy będą one po koli na przykład takie b, a, c (będzie a, b ,c). Ale gdy "origin" dębą po kolei takie c, b, a, funkcja zamieni strukturę z origin wynoszącym c na strukturę origin wynoszącym b, pozostawiając tą strukturę (będzie b, b, a zamiast a, b, c). W innych wypadkach w ogóle nic nie robi. Co zrobić, aby funkcja sortowała poprawnie? Chciałbym, aby struktury plant były sortowane w table:

a) najpierw według "origin" alfabetycznie, b) potem według "id" malejąco, gdy sortingByName = 0, c) potem według "name" alfabetycznie, gdy sortingByName = 1.

Rekman19.04.2009 14:20:02
#
Dołączył: 05.04.2009

Przyglądnijmy się funkcji SortAndDisplay(). Najpierw indeksowanie zamienianych elementów. Zmienna x i temp ulega zmianie za każdym razem, gdy jest spenłniony warunek sortowania (pomińmy na razie jego poprawność). Niezależnie od warunku sortowania, ale z uwzględnieniem zmian jakie ten warunek wprowadza, w każdym przebiegu wewnętrznej pętli są zamieniane elementy w tablicy table według poniższych instrukcji: table[x] = table [i]; table [i] = temp; Wygląda to na typową zamianę elementów w tablicy. Ale tak nie jest. Indeks przechowywany w zmiennej i do końca wykonywania wewnętrznej pętli nie ulega zmianie w przeciwieństwie do indeksu w zmiennej x i elementu w temp: if (warunek_sortowania) { x = j; temp = table[j]; } Jeżeli w jakimś kroku będzie spełniony warunek sortowania, a w następnym - nie, to powyższe instrukcje skopiują ten sam elementy do dwóch różnych pól tablicy! A wtedy element o indeksie x zostanie utracony!

A teraz warunek sortowania: if (strcmp(table[j].origin, temp.origin) < 0 && ((sortingByName == 0 && table[j].id > temp.id) || (sortingByName == 1 && strcmp(table[j].name, temp.name) < 0))) Sortowanie (zamiana elementów) ma miejsce tylko wówczas, gdy oba warunki są spełnione. Przy czym pole origin elementu porównywanego z wzorcem przechowywanym w zmienne temp musi być mniejsze a pole id większe lub pole name mniejsze. A co z elementami, których pola origin są równe a pole id jest większe lub pole name mniejsze? Takie elemnety nie będą sortowane! A właśnie takie elementy stanowią grupę. Nie będą też sortowanne elementy o różnych polach origin, gdy pole id elementu porównywanego będzie mniejsze lub pole name będzie większe.

Poniżej przykładowy, poprawny, ale nieefektywny algorytm sortowania: for(i=0; i<number-1; ++i) { temp = table [i]; for(j=i+1; j<number; ++j) { if(strcmp(table [i].origin, temp.origin) < 0) { table [i] = table[j]; table[j] = temp; temp = table [i]; } else if(strcmp(table [i].origin, temp.origin) == 0) { if ((sortByName == 0 && table [i].id > temp.id) || (sortByName == 1 && strcmp(table [i].name, temp.name))) { table [i] = table[j]; table[j] = temp; temp = table [i]; } }

}

}

Do sortowania tablic o dowolnej zawartości można użyć funkcji qsort() ze standardowej biblioteki języka C (plik stdlib.h).




Kontakt

Jeśli chcesz się z nami skontaktować napisz na adres: info(at)binboy.org lub odwiedź nasz profil na Facebooku!

O Nas

Serwis binboy.org to kopalnia wiedzy dla wszystkich z branży IT, w szczególności dla programistów i webmasterów. To duży zbiór kursów programowania, tutoriali, darmowych ebooków, setki kodów źródłowych itp.

Bądź w kontakcie

Panel użytkownika

Zaloguj się do panelu użytkownika.
Nie masz konta? Zarejestruj się!
Zapomniałeś hasła?