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])
  y = x[4];

 if(y < x[5])
  y = x[5];

 // itd. aż do x[12]

 ShowMessage("Największa liczba to: " + IntToStr(y));
}

//--------------------------------

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