Zacznijmy od początku, weźmy na warsztat taki oto kod:
#include <iostream>
#include <algorithm>
#define N 7
using namespace std;
int main() {
int tab[N]={5,7,2,1,0,3,-5};
sort(tab,tab+N);
for(int i=0;i<N;i++)
{
cout<<tab[i]<<" ";
}
return 0;
}
Program ten nie robi nic innego jak sortuje tablice o nazwie tab za pomocą funkcji sort. Funkcja ta przyjmuje minimalnie dwa argumenty, maksymalnie trzy. Pierwszy argument to adres na początek zakresu do posortowania zaś drugi to wskaźnik na koniec zakresu. Opcjonalny, trzeci argument to wskaźnik na funkcję. Funkcja ta ma jednoznacznie określać, jak funkcja sort ma porównywać między sobą dwa elementy. W przypadku typów wbudowanych takich jak int, double itp nie jest konieczne tworzenie własnej funkcji porównującej. Standardowo funkcja sort sortuje elementy rosnąco.
Co jeśli chcieli byśmy sortować elementy w inny, przez nas określony sposób np. malejąco.
#include <iostream>
#include <algorithm>
#define N 7
using namespace std;
bool por(const int& a,const int& b)
{
if(a>b)
{
return true;
}
else
{
return false;
}
}
int main() {
int tab[N]={5,7,2,1,0,3,-5};
sort(tab,tab+N,por);
for(int i=0;i<N;i++)
{
cout<<tab[i]<<" ";
}
return 0;
}
W tym przypadku nie obyło się bez stworzenia własnej funkcji porównującej. Warto sobie zapamiętać, że funkcja ta zawsze zwraca wartość typu bool oraz przyjmuje dwa argumenty. Argumenty te muszą być tego samego typu co sortowana kolekcja. W powyższym kodzie argumenty są typu int (użyłem referencji by nie dochodziło do tworzenia się niepotrzebnych kopii).
Weźmy teraz na warsztat sortowanie tablicy zawierającej obiekty jakiejś klasy. Spójrz na poniższy kod:
#include <iostream>
#include <algorithm>
#define N 3
using namespace std;
class Punkt2d
{
public:
int x,y;
Punkt2d(int X,int Y):x(X),y(Y){}
void wypisz()
{
cout<<x<<","<<y<<endl;
}
};
int main() {
Punkt2d tab[N]={Punkt2d(3,7),Punkt2d(-2,7),Punkt2d(7,7)};
sort(tab,tab+N);//ta linia jest bledna
for(int i=0;i<N;i++)
{
tab[i].wypisz();
}
return 0;
}
Tworzymy klasę reprezentującą punkt na płaszczyźnie 2D. Następnie tworzymy tablicę zawierającą trzy obiekty tej klasy. W kolejnej linii wywołujemy funkcję sort. Wydawać by się mogło, że wszystko jest ok, niestety program ten nie skompiluje się poprawnie. Problemem jest to, że funkcja sort nie potrafi, nie wie jak ma porównywać elementy sortowanej tablicy. Musimy ją tego nauczyć przez zdefiniowanie funkcji porównującej.
#include <iostream>
#include <algorithm>
#define N 3
using namespace std;
class Punkt2d
{
public:
int x,y;
Punkt2d(int X,int Y):x(X),y(Y){}
void wypisz()
{
cout<<x<<","<<y<<endl;
}
};
bool por(const Punkt2d & a,const Punkt2d & b)
{
if(a.x<b.x)
{
return true;
}
else
{
return false;
}
}
int main() {
Punkt2d tab[N]={Punkt2d(3,7),Punkt2d(-2,7),Punkt2d(7,7)};
sort(tab,tab+N,por);
for(int i=0;i<N;i++)
{
tab[i].wypisz();
}
return 0;
}
Powyższy kod kompiluje się, sortowane są obiekty klasy Punkt2d względem pola x, rosnąco.
Co ciekawe istnieje sposób na to, aby można było nauczyć funkcję sort jak ma sortować elementy kolekcji bez podawania trzeciego argumentu. Wystarczy, że wewnątrz klasy przeciążymy operator <. Kod zawierający takie przeciążenie znajduje się poniżej:
#include <iostream>
#include <algorithm>
#define N 3
using namespace std;
class Punkt2d
{
public:
int x,y;
Punkt2d(int X,int Y):x(X),y(Y){}
bool operator<(const Punkt2d other)const
{
if(this->x<other.x)
{
return true;
}
else
{
return false;
}
}
void wypisz()
{
cout<<x<<","<<y<<endl;
}
};
int main() {
Punkt2d tab[N]={Punkt2d(3,7),Punkt2d(-2,7),Punkt2d(7,7)};
sort(tab,tab+N);
for(int i=0;i<N;i++)
{
tab[i].wypisz();
}
return 0;
}