====== Algorytm partial_sort ======
===== Plik nagłówkowy =====
#include
===== Deklaracja funkcji =====
template
void partial_sort(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last);
template
void partial_sort(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last, Compare comp);
===== Parametry funkcji =====
* RandomAccessIterator first
Iterator wskazujący na początek zakresu częściowego sortowania w kolekcji.
* RandomAccessIterator middle
Iterator wskazujący, ile elementów przed nim ma być posortowane.
* RandomAccessIterator last
Iterator wskazujący na koniec zakresu częściowego sortowania w kolekcji.
* Compare comp
Zewnętrzna funkcja lub funktor, służąca do porównywania elementów w kolekcji.
===== Wartość zwracana =====
Brak.
===== Opis algorytmu =====
Przemieszcza elementy w kolekcji w zakresie [**first**, **last**) tak, że w zakresie [**first**, **middle**) zawiera najmniejsze elementy z całego zakresu sortowania kolekcji, a w zakresie [**middle**, **last**) znajdują się pozostałe, nieuporządkowane elementy.
Do porównywania obiektów w kolekcji funkcja wykorzystuje albo zdefiniowany dla obiektu operator mniejszości w pierwszej wersji funkcji, albo zewnętrzną funkcję/funktor porównujący w wersji drugiej.
==== Złożoność algorytmu ====
Do sortowania elementów wykorzystano algorytm **heapsort**, więc jego złożoność można oszacować wg poniższego wzoru:
O = (last - start)*log(middle - start)
===== Przykłady użycia =====
==== Przykład pierwszy ====
W tym przykładzie użyto pierwszej wersji omawianej funkcji do odnalezienia 4 najmniejszych liczb całkowitych typu **int** w kolekcji:
vector first; //Kolekcja liczb całkowitych
vector::iterator iter; //Iterator do tej kolekcji
/* Wypełnianie kolekcji przykładowymi liczbami */
first.push_back(23);
first.push_back(16);
first.push_back(54);
first.push_back(21);
first.push_back(14);
first.push_back(38);
first.push_back(63);
first.push_back(29);
cout << "Przyklad pierwszy\n\n";
cout << "Liczby calkowite 'int':\n\n";
/* Wyświetlenie zawartości kolekcji */
for (iter = first.begin(); iter != first.end(); ++iter)
cout << *iter << " ";
/* out: 23 16 54 21 14 38 63 29 */
/* Sortowanie kolekcji, do uzyskania 4 posortowanych elementów */
partial_sort(first.begin(), first.begin() + 4, first.end());
cout << "\n\nDane czesciowo posortowane - pierwsze 4 elementy:\n\n";
/* Wyświetlenie zawartości częściowo posortowanej kolekcji */
for (iter = first.begin(); iter != first.end(); ++iter)
cout << *iter << " ";
/* out: 14 16 21 23 54 38 63 29 */
==== Przykład drugi ====
W tym przykładzie sortowana będzie kolekcja następujących obiektów, modelujących kartę pacjenta:
/* Rodzaj sortowania */
enum SortBy {byName, byAge, byWeight};
class PatientCard {
private:
string name; //Nazwisko
int age; //Wiek
double weight; //Waga
static SortBy sort; //Rodzaj sortowania
public:
/* Konstruktor zerowy. */
PatientCard() : name("name"), age(0), weight(0.0) {}
/* Konstruktor inicjujący. */
PatientCard(const string& _name, const int& _age, const double& _weight) :
name(_name), age(_age), weight(_weight) {}
const string& getName() const { //Zwraca nazwisko
return name;
}
const int getAge() const { //Zwraca wiek
return age;
}
const double getWeight() const { //Zwraca wagę
return weight;
}
void setSort(SortBy _sort) { //Ustala rodzaj sortowania
sort = _sort;
}
/* Operator mniejszości, służący do porównywania w algorytmie. Porównuje
odpowiednie pola dwóch obiektów, zwraca 'true', jeśli są uporządkowane
rosnąco, i 'false', jeśli nie. Do wyboru pól do porównywania służy pole
'sort'. */
bool operator<(const PatientCard& _card) {
switch (sort) {
case byName:
if (name.compare(_card.name) < 0)
return true;
break;
case byAge:
if (age < _card.age)
return true;
break;
case byWeight:
if (weight < _card.weight)
return true;
break;
default:
return false;
}
return false;
};
/* Zaprzyjaźniony operator, pozwalający na wysłanie danych obiektu do
strumienia wyjściowego. */
friend ostream& operator<<(ostream& _cout, const PatientCard& _card);
};
SortBy PatientCard::sort = byName; //Inicjacja statycznego pola 'sort'
/* Zaprzyjaźniony operator. */
ostream& operator<<(ostream& _cout, const PatientCard& _card) {
_cout << _card.name << "\n\t\twiek: " << _card.age << "\twaga: " << _card.weight << endl;
return _cout;
}
int main() {
vector second; //Kolekcja kart pacjenta
vector::iterator iter2; //Iterator do tej kolekcji
/* Wypełnienie kolekcji przykładowymi danymi */
second.push_back(PatientCard("Wilson", 32, 78.5));
second.push_back(PatientCard("Pearson", 27, 63.2));
second.push_back(PatientCard("Kingsley", 43, 89.0));
second.push_back(PatientCard("Smith", 18, 57.4));
second.push_back(PatientCard("Wiliams", 22, 82.1));
second.push_back(PatientCard("Crouch", 37, 102.6));
second.push_back(PatientCard("Michelson", 64, 96.4));
second.push_back(PatientCard("Bright", 54, 60.5));
vector third = second; //Kolejne kolekcje
vector fourth = second;
=== Sortowanie wg wbudowanego operatora mniejszości ===
Tu sortowanie odbywa się przy użyciu wbudowanego operatora mniejszości, który przy obecnym ustawieniu pola **sort** sortuje karty alfabetycznie. Chcemy zatem uzyskać trzy pierwsze karty:
partial_sort(second.begin(), second.begin() + 3, second.end());
/* out: Bright
wiek: 54 waga: 60.5
Crouch
wiek: 37 waga: 102.6
Kingsley
wiek: 43 waga: 89
Wiliams
wiek: 22 waga: 82.1
Smith... */
=== Sortowanie wg zewnętrznej funkcji porównującej ===
W tym przypadku zdefiniowano zewnętrzną funkcję, służącą do porównywania kart i sortowania ich według malejącej wagi:
bool compareCard(const PatientCard& _a, const PatientCard& _b) {
if (_a.getWeight() > _b.getWeight())
return true;
return false;
}
Chcemy uzyskać cztery karty o największej wadze:
partial_sort(third.begin(), third.begin() + 4, third.end(), compareCard);
/* out: Crouch
wiek: 37 waga: 102.6
Michelson
wiek: 64 waga: 96.4
Kingsley
wiek: 43 waga: 89
Wiliams
wiek: 22 waga: 82.1
Smith
wiek: 18 waga: 57.4
Pearson
wiek: 27 waga: 63.2
... */
=== Sortowanie wg zdefiniowanego funktora ===
Funktor, czyli obiekt funkcyjny, to taki obiekt, który ma zdefiniowany operator **operator()**. W ogólnym przypadku funktor może przechowywać stan, który może mieć wpływ na działanie tego operatora, w przeciwieństwie do stałej w działaniu funkcji porównującej. W tym przypadku jednak ograniczono się do najprostszego przypadku funktora:
class functorCard {
public:
bool operator()(const PatientCard& _a, const PatientCard& _b) {
if (_a.getAge() > _b.getAge())
return true;
return false;
}
};
Jak widać, funktor umożliwia sortowanie wg malejącego wieku. Chcemy uzyskać pięć kart o największym wieku:
partial_sort(fourth.begin(), fourth.begin() + 5, fourth.end(), functorCard());
/* out: Michelson
wiek: 64 waga: 96.4
Bright
wiek: 54 waga: 60.5
Kingsley
wiek: 43 waga: 89
Crouch
wiek: 37 waga: 102.6
Wilson
wiek: 32 waga: 78.5
Smith
wiek: 18 waga: 57.4
Wiliams
wiek: 22 waga: 82.1
... */
===== Podsumowanie =====
Algorytm **partial_sort** umożliwia wyodrębnienie **n** skrajnych elementów w danej kolekcji na podstawie pewnego kryterium, określonego za pomocą operatora mniejszości **operator<**, funkcji porównującej bądź funktora. Dzięki temu, nie trzeba sortować całej kolekcji, wystarczy sortowanie do momentu uzyskania żądanej ilości elementów, co skraca sam czas trwania operacji.
===== Źródła =====
Plik źródłowy z przykładami: {{:stl_algorytmy:partial_sort2.cpp}}
----
//[[alaskow1@stud.elka.pw.edu.pl|Artur Marcin Laskowski]] 2008/12/12 13:48//