WYSZUKIWANIE NAJWIĘKSZEJ LICZBY
Ktoś zaraz zapyta co to za filozofia wyszukać największą liczbę, jeżeli mamy np. zbiór liczb: 1, 2, 5, 10, 16, 8, 24, 32, 100, 60, 3, 9, 11, to bez problemu wskażemy na liczbę 100 ponieważ jest w tym zbiorze liczbą o najwyższej wartości. Teraz jednak zastanówcie się przez chwilę, jak można zrealizować to zadanie w programie komputerowym, jak program ma wskazać w takim zbiorze liczbę największą, oczywiście można by to zrobić np. tak:
| // Plik źródłowy np. Unit1.cpp //-------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { int x[] = {1, 2, 5, 10, 16, 8, 24, 32, 100, 60, 3, 9, 11}; int y; if(x[0] < x[1]) y = x[1]; else y = x[0]; if(y < x[2]) y = x[2]; if(y < x[3]) y = x[3]; if(y < x[4]) // itd. aż do x[12] |
Oczywiście można tworzyć takie ciągi, sprawdzające czy kolejna liczba jest większa od poprzedniej, ale byłoby to wyjątkowo uciążliwe gdyby zbiór zawierał np. kilka tysięcy liczb, no a poza tym nie dałoby się tej metody zastosować w przypadku gdy nie wiemy ile liczb znajduje się w zbiorze. Jednak już na podstawie powyższego przypadku można wysnuć wniosek, że to zadanie da się rozwiązać w znacznie prostszy sposób, np. za pomocą pętli, więc używając tego samego wzoru można by zrobić to tak:
| // Plik źródłowy np. Unit1.cpp //-------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { int x[] = {1, 2, 5, 10, 16, 8, 24, 32, 100, 60, 3, 9, 11}; int y = 0; for(int i = 0; i <= 12; i++) if(y < x[i]) y = x[i]; ShowMessage("Największa liczba to: " + IntToStr(y)); } //-------------------------------- |
Jak widać jest tu znacznie mniej kodu, jednak nadal pozostaje jeden problem, otóż rozmiar tablicy (zbioru) jest jawnie określany, czyli musimy podać w pętli ile elementów zawiera tablica (w przykładzie 12). Oczywiście można to zrobić nieco inaczej, i są tutaj dwie metody, pierwsza metoda pozwala określić rozmiar tablicy poprzez wykorzystanie operatora czasu kompilacji sizeof(), drugi sposób to wykorzystanie makrodefinicji ARRAYSIZE(), określający rozmiar tablicy będącej jej argumentem:
| // Plik źródłowy np. Unit1.cpp // Wykorzystanie operatora czasu kompilacji. //-------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { int x[] = {1, 2, 5, 10, 16, 8, 24, 32, 100, 60, 3, 9, 11}; int y = 0; const int c = (sizeof(x) / sizeof(x[0])) - 1; for(int i = 0; i <= c; i++) if(y < x[i]) y = x[i]; ShowMessage("Największa liczba to: " + IntToStr(y)); } //-------------------------------- |
| // Plik źródłowy np. Unit1.cpp // Wykorzystanie makrodefinicji //-------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { int x[] = {1, 2, 5, 10, 16, 8, 24, 32, 100, 60, 3, 9, 11}; int y = 0; const int c = ARRAYSIZE(x) - 1; for(int i = 0; i <= c; i++) if(y < x[i]) y = x[i]; ShowMessage("Największa liczba to: " + IntToStr(y)); } //-------------------------------- |
To by było na tyle, jeżeli chodzi o tablice. Załóżmy jednak, że mamy zbiór liczb w pliku tekstowym, zapisanych w jednej kolumnie i spróbujmy odczytać je z pliku i wskazać największą liczbę, zadanie jest znacznie prostsze:
Plik tekstowy
| 1 2 5 10 16 8 24 32 100 60 3 9 11 |
| // Plik źródłowy np. Unit1.cpp //-------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { TStringList *Lista = new TStringList; Lista->LoadFromFile("Nazwa_pliku.txt"); int y = 0; for(int i = 0; i < Lista->Count; i++) { int x; try { x = Lista->Strings[i].ToInt(); } catch(...) { x = 0; } if(y < x) y = x; } ShowMessage("Największa liczba to: " + IntToStr(y)); } //-------------------------------- |
Ktoś może zapytać, ale co jeśli mamy do czynienia z liczbami ujemnymi? Jeżeli w takim przypadku przypiszemy zmiennej y wartość 0, to jak łatwo zgadnąć 0 jest większe od jakiejkolwiek liczby ujemnej i algorytm nie będzie działał prawidłowo ponieważ zawsze wskaże liczbę 0. W takiej sytuacji wystarczy przypisać zmiennej y pierwszą liczbę z tablicy i niezależnie od tego jaka to będzie liczba, algorytm i tak wskaże tą największą. Dlaczego? Dlatego, że jeżeli np. pierwsza liczba jest tą największą to w dalszej części algorytmu nie będzie się ona zmieniała, a jeżeli nie to algorytm i tak przypisze do zmiennej y inną liczbę na którą natrafi, a która będzie większa od tej pierwszej:
| // Plik źródłowy np. Unit1.cpp //-------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { TStringList *Lista = new TStringList; Lista->LoadFromFile("Plik.txt"); int y; try { y = Lista->Strings[0].ToInt(); } catch(...) { y = 0; } for(int i = 0; i < Lista->Count; i++) { int x; try { x = Lista->Strings[i].ToInt(); } catch(...) { x = 0; } if(y < x) y = x; } ShowMessage("Największa liczba to: " + IntToStr(y)); } //-------------------------------- |
Być może niektórzy już zauważyli, że algorytm posiada pewien dość istotny mankament, otóż jeżeli w pliku oprócz liczb będą znajdowały się również litery, to jak to widać w algorytmie zmiennej x zostanie przypisana wartość 0, a taka liczba może wogóle nie występować w tablicy, dlatego logicznym wydaje się, żeby tej zmiennej nie przypisywać żadnej wartości, ale to również nie jest dobrym pomysłem, znacznie lepiej będzie przypisać zmiennej x to co znajduje się w zmiennej y. Inna rzecz to zmienna y, która pobiera na samym początku pierwszą liczbę z tablicy, co jednak jeżeli na pierwszym miejscu w tablicy będzie się znajdowała litera, otóż wtedy do zmiennej zostanie przypisana wartość 0 i znów pojawia się ten sam problem. Rozwiązanie problemu polega na tym, że trzeba do zmiennej y przypisać pierwszą liczbę jaką napotka
w tablicy nie będącą literą, a nie pierwszy element tablicy:
...poprawiono
drobny błąd w tym algorytmie...
| // Plik źródłowy np. Unit1.cpp //-------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { TStringList *Lista = new TStringList; Lista->LoadFromFile("Plik.txt"); int y; bool litery = true; for(int i = 0; i < Lista->Count; i++) { try { y = Lista->Strings[i].ToInt(); litery = false; break; } catch(...){;} } if(litery) { ShowMessage("Zbiór nie zawiera liczb, znajdują się w nim wyłącznie litery!"); return; } for(int i = 0; i < Lista->Count; i++) { int x; try { x = Lista->Strings[i].ToInt(); } catch(...) { x = y; } if(y < x) y = x; } ShowMessage("Największa liczba to: " + IntToStr(y)); } //-------------------------------- |
A co jeżeli zbiór będzie zawierał zarówno liczby ujemne i dodatnie? Nic! W takim przypadku liczby ujemne się nie liczą, bo największa liczba ujemna jest i tak mniejsza od zera, więc w takim przypadku można wykorzystać algorytm na wyszukiwanie liczb dodatnich.
Do wyszukiwania najmniejszej liczby w zbiorze można wykorzystać ten sam algorytm, wystarczy tylko zmienić jedną linię kodu, a mianowicie: if(y < x) należy zamienić na: if(y > x):
| // Plik źródłowy np. Unit1.cpp //-------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { int x[] = {1, 2, 5, 10, 16, 8, 24, 32, 100, 60, 3, 9, 11}; int y = x[0]; for(int i = 0; i <= 12; i++) if(y > x[i]) y = x[i]; ShowMessage("Najmniejsza liczba to: " + IntToStr(y)); } //-------------------------------- |
Oczywiście w takim przypadku nie należy przypisywać zmiennej y wartości 0, ponieważ może ona nie występować w zbiorze liczb, a jak wiadomo zero jest najmniejszą z liczb dodatnich.
Opracował: Cyfrowy Baron