Quicksort

Lecții de algoritmică, tips & tricks

Quicksort

Postby Cosmin_NTG » 01 Aug 2011, 21:18

Quicksort

-Tutorial-


Acest tutorial este destinat tuturor celor ce vor sa aprofundeze cunostintele legate de algoritmii de sortare prin imbogatirea acestora cu un algoritm pe cat de simplu, pe atat de eficient (quicksort).

Cunoscuta si sub numele de sortarea prin partitionare, quicksort este o metoda de sortare rapida, de unde deriva si numele.

Cu o complexitate medie de O(n log n), quicksort este alegerea optima de fiecare data cand se intalnesc probleme de sortare.
Algoritmul metodei imbina caracterul simplist cu performantele, ceea ce denota atat o usoara intelegere a algoritmului cat si performante destul de mari.

Pentru inceput, vom analiza aproximativ linie cu linie urmatorul cod in limbajul de programare C++:
  1. void quicksort(int v[100], int stanga, int dreapta)
  2. {
  3.    int i, j, mijloc, aux;         // variabilele
  4.    i=stanga;                       //  initializarea
  5.    j=dreapta;                    //   indicilor
  6.    mijloc=v[(stanga+dreapta)/2];  // initializarea variabilei - pivot
  7.   while(i<=j)
  8.   {
  9.    while(v[i]<mijloc)  // apropierea i-ului de mijloc
  10.       i++;
  11.    while(v[j]>mijloc)   // apropierea j-ului de mijloc
  12.       j--;
  13.     if(i<=j)   //conditia efectuarii operatiei de interschimbare
  14.     {
  15.        aux=v[i];
  16.        v[i]=v[j];   // operatia de interschimbare
  17.        v[j]=aux;
  18.        i++;
  19.        j--;
  20.      }
  21.   }                    
  22.  if(stanga<j)                    //recursivitatea            
  23.    quicksort(v, stanga, j);   // in partea stanga    
  24.  if(i<dreapta)                    
  25.    quicksort(v, i, dreapta);  // in partea dreapta
  26.  
  27. }


Aceasta functie este implementarea in C++ a algoritmului metodei de sortare quicksort.

  1. void quicksort(int v[100], int stanga, int dreapta)

Aceasta linie reprezinta antetul functiei. Dupa cum se observa, functia este declarata void pentru ca
nu trebuie sa intoarca nici un rezultat, ci doar sa modifice pozitia elementelor din vector.
Functia primeste 3 parametri: primul este vectorul ce trebuie sortat, al doilea este un numar ce reprezinta indexul primului element din vector (cel din stanga) iar al treilea este, de asemenea, un numar ce reprezinta indexul ultimului element din vector (cel din dreapta).


Pentru a parcurge algoritmul, sunt necesare 4 variabile: o variabila ( i ) cu rolul de a parcurge vectorul (vorbind la modul general) spre dreapta prin incrementare ( i + + ); o variabila ( j ) cu rolul de a parcurge vectorul spre stanga prin decrementare ( j - - ); o variabila (mijloc) cu rolul de pivot, mai exact cu rolul de a partitiona, de a imparti vectorul in parti mai mici ce urmeaza a fi sortate ulterior si o variabila auxiliara ( aux ) cu rolul de a pastra temporar valorile elementelor ce vor interveni in operatia de interschimbare.


In aceste doua operatii, variabilele i si j sunt initializate cu valorile parametrilor primiti de functie "stanga" respectiv "dreapta".
Motivul pentru care in algoritm nu sunt utilizati parametrii in mod direct (in loc de variabilele i si j) este reprezentat de faza recursiva a algoritmului unde valorile initiale ale parametrilor amintiti mai sus sunt indispensabile.

  1. mijloc=v[(left+right)/2];

Aceasta linie reprezinta initializarea variabilei - pivot cu o valoare apropiata de mijlocul vectorului (nu trebuie neaparat sa fie exact mijlocul). Aceasta valoare va deveni o valoare - reper in operatia de parcurgere a vectorului.


Algoritmul este structurat in 3 instructiuni repetitive cu numar necunoscut de pasi si cu test initial (while). Prima structura este una de ansamblu in care se afla celelalte doua plus operatia de interschimbare. Aceasta structura de ansamblu are rolul de a "monitoriza" pozitia indicilor (i si j) si de a participa la partitionarea vectorului.

  1. while(v[i]<mijloc)
  2.      i++;
  3. while(v[j]>mijloc)
  4.      j--;

Urmatoarele doua instructiuni repetitive au rolul de a apropia indicii de variabila - pivot aflata aproape de mijlocul vectorului.
Prima instructiune apropie i-ul de mijloc iar a doua apropie j-ul. Aceste doua instructiuni participa constructiv la eficientizarea algoritmului din punct de vedere al timpului de executie.

  1. if(i<=j)
  2. {
  3.      aux=v[i];
  4.      v[i]=v[j];
  5.      v[j]=aux;
  6.      i++;
  7.      j--;
  8. }

Aceasta bucata de cod reprezinta operatia de interschimbare. Este mai degraba o operatie mai complexa dat fiind faptul ca este compusa din mai multe operatii de atribuire. Rolul acesteia este acela de interschimba valorile elementelor vectorului atunci cand cele doua instructiuni repetitive pozitionate inaintea acestei operatii permit acest lucru.

  1. if(stanga<j)
  2.      quicksort(v, stanga, j);
  3. if(i<dreapta)
  4.      quicksort(v, i, dreapta);

Algoritmul se incheie, dupa cum se observa cu doua instructiuni conditionale ce verifica daca valorile indicilor rezultate dupa operatiile din cadrul algoritmului se incadreaza in partile corespunzatoare lor din vector (i-ul va trece in dreapta prin incrementare, deci trebuie sa fie mai mic decat parametrul initial "dreapta" primit de functie, iar j-ul trece in stanga prin decrementare, deci trebuie sa fie mai mare decat parametrul "stanga" primit initial de functie ).

Pentru a va ajuta sa intelegeti mai bine algoritmul, am creat urmatoarele diagrame sugestive ce reprezinta pozitia si valoarea variabilelor implicate direct in algoritm la fiecare parcurgere:
Image

In acest pas ne aflam in momentul in care vectorul este nesortat inainte de inceperea primei parcurgeri.

Image

Pasul 2 reprezentat in imaginea de mai sus descrie apropierea de mijloc a celor doi indici i si j asta insemnand mai exact parcurgerea celor doua while-uri pozitionate inaintea operatiei de interschimbare.
Explicatie:

Dupa cum am vazut in primul pas, mijlocul ia valoarea v[(stanga + dreapta)/2] ceea ce inseamna v[ (0 + 6)/2] adica v[3] care este egal cu 3.
La intrarea in primul while despre care am vorbit mai sus (cel care incrementeaza i - ul), valoarea lui i este 0 (zero) iar conditia instructiunii repetitive ( v[0]<mijloc ) nu este indeplinita deoarece v[0]=4 care este mai mare decat 3 (mijlocul) prin urmare, primul while nu este parcurs. De aceea in pasul 2 ( pasul de fata ) i - ul ramane 0 (zero) pentru ca nu se incrementeaza.
In mod analog, la intrarea in al doilea while se observa ca v[ j ] > mijloc ceea ce permite parcurgerea instructiunii ( adica decrementarea j -ului) insa parcurgerea are loc doar o singura data pentru ca dupa decrementare, j-ul devine 5 iar v[5] = 2 care este mai mic decat 3 deci conditia nu mai este indeplinita.

Image

Imaginea de mai sus este destul de sugestiva. Dupa o scurta analiza a pasului 2 de mai sus, se observa ca i-ul este 0 (zero) iar j-ul 5. Acest lucru satisface conditia necesara efectuarii operatiei de interschimbare. Prin urmare, are loc interschimbarea intre v[ 0] si v[ 5 ].

Image

In iteratia 1, primul pas este reprezentat de cele doua while-uri (exact ca in pasul 1 al parcurgerii initiale). Valoarea lui i este 1 pentru ca s-a incrementat in operatia de interschimbare din parcurgerea precedenta iar v[1] nu este mai mic decat variabila mijloc ( 6 > 3 ) deci nu se incrementeaza. Pe de alta parte, j-ul fiind decrementat din operatia de interschimbare se decrementeaza din nou, v[j] fiind mai mare decat variabila mijloc ( 5 > 3 ).

Image

Operatia de interschimbare din iteratia 1.

Image

Primul pas din iteratia a doua impune nerespectarea ( i > j ) a doua conditii identice: cea a instructiunii repetitive de ansamblu si cea a operatiei de interschimbare.

Image

Dupa cum clar se observa, vectorul s-a impartit in doua, lucru impus de recursivitate. Imediat ce i-ul depaseste valoare j-ului, in vector se individualizeaza doua parti: prima este marginita de parametrul initial primit de functie (stanga) si de j (care s-a decrementat ) iar a doua parte este marginita de i (care s-a incrementat) si de celalalt parametru primit initial de functie (dreapta). In final, apelarea functiei prin parametrii ce marginesc cele doua parti, fac posibila sortarea integrala a vectorului de unde si numele de sortare prin partitionare . Urmarorii pasi sunt exact cei descrisi mai sus, aplicatii separat pe cele doua partitii formate.
In final, vectorul sortat va avea forma:
Image

Pentru a va ajuta sa intelegeti mai bine algoritmul quicksort, va recomand urmatorul program:
http://www.cs.oswego.edu/~mohammad/classes/csc241/samples/sort/Sort2-E.html
Se numeste "Sort Animation" si este un program structurat destul de inteligent: In partea stanga este algoritmul (functia in C++) unde fiecare linie este colorata in momentul cand programul o parcurge iar in partea dreapta se afla vectorul cu pozitia fiecarui element si valoarea tuturor variabilelor din program. Exista optiuni de setare a vitezei de parcurgere a algoritmului cat si de schimbare a acestuia cu alte 3 metode de sortare cunoscute

Sper ca m-am facut inteles. Spor la invatat !
Cosmin_NTG
6p / 1 votes
Thinking about solutions is better than thinking about problems
User avatar
Cosmin_NTG
Byte
 
Joined: 11 Jan 2011
Location: 192.2L1.44G
Status: 10

Re: Quicksort

Postby morpheus » 02 Aug 2011, 01:20

Pentru variatie, o implementare C folosind algoritm de partitionare Lomuto si median of three:
  1.  
  2. #include <stdio.h>
  3.  
  4. #define SWAP(x, y, type)  \
  5. do                        \
  6. {                         \
  7.     type __temp = x;      \
  8.     x = y;                \
  9.     y = __temp;           \
  10. } while(0);
  11.  
  12. #define PARTITION_MEDIAN_OF_THREE(a, first, last, pivot, type)   \
  13. do                                                               \
  14. {                                                                \
  15.     type __first = first;                                        \
  16.     type __last = last;                                          \
  17.     type __mid = __first + (__last - __first) / 2;               \
  18.     type __pivot = a[__first] > a[__mid] ? __first : __mid;      \
  19.     if (a[__pivot] > a[__last])                                  \
  20.         __pivot = __last;                                        \
  21.     SWAP(a[__pivot], a[__first], type);                          \
  22.     __pivot = __first;                                           \
  23.     while (__first < __last)                                     \
  24.     {                                                            \
  25.         if (a[__first] <= a[__last])                             \
  26.         {                                                        \
  27.             SWAP(a[__pivot], a[__first], type);                  \
  28.             ++__pivot;                                           \
  29.         }                                                        \
  30.         ++__first;                                               \
  31.     }                                                            \
  32.     SWAP(a[__pivot], a[__last], type);                           \
  33.     pivot = __pivot;                                             \
  34. }                                                                \
  35. while(0);
  36.  
  37.  
  38. void quicksort(int a[], int first, int last)
  39. {
  40.     if (first < last)
  41.     {
  42.         int pivot;
  43.         PARTITION_MEDIAN_OF_THREE(a, first, last, pivot, int);
  44.         quicksort(a, first, pivot - 1);
  45.         quicksort(a, pivot + 1, last);
  46.     }
  47. }
  48.  
  49. void display(int a[], size_t size)
  50. {
  51.     int i;
  52.     for (i = 0; i < size; ++i)
  53.         printf("%d\n", a[i]);
  54. }
  55.  
  56. int main()
  57. {
  58.     int a[] = {9,8,6,7,0,1,2,4,5,3};
  59.     printf("Before sorting:\n");
  60.     display(a, 10);
  61.     quicksort(a, 0, 9);
  62.     printf("After sorting:\n");
  63.     display(a, 10);  
  64.     return 0;
  65. }
  66.  


PS: ^poti sa demonstrezi ca Quicksort e O(n^2) in cazul cel mai defavorabil si O(n * log n) in medie ?
Eventual, discuta si despre stabilitate.
0,0p / 0 votes
User avatar
morpheus
Word
 
Joined: 30 Dec 2009
Location: Bucharest, Romania
Status: 54.84

Re: Quicksort

Postby Cosmin_NTG » 02 Aug 2011, 12:38

Intr-adevar nu pot demonstra acest lucru (si nici nu vreau sa aberez o demonstratie cu niste lucruri neintelese de pe net) pentru ca imi trebuie cunostinte despre logaritmi, combinari and stuff care se fac in clasa a 10-a iar eu abia am trecut a 10-a. Eu stiam (stiu) ca motivul pentru care complexitatea este de O(n log n) il reprezinta faptul ca se executa n log n operatii. De aceea este o complexitate medie. Dar nu vreau sa aberez, cum am spus mai sus. Mi s-a parut important acest aspect al complexitatii si de aceea l-am si punctat in tutorial insa astfel de demonstratii ma cam depasesc (pentru moment >:)) .
0,0p / 0 votes
Thinking about solutions is better than thinking about problems
User avatar
Cosmin_NTG
Byte
 
Joined: 11 Jan 2011
Location: 192.2L1.44G
Status: 10

Re: Quicksort

Postby cata45 » 06 Aug 2011, 15:28

Incerc sa folosesc QS pentru a sorta niste coordonate.
Ceva de genul:

Algoritmul construit de mine le sorteaza doar dupa x. In cazul de mai sus raman exact lafel. Cum as putea sa le sortez si dupa x si dupa y? (adica daca x-si sunt egali sa ordoneze in functie de y) Pe exemplul de mai sus sa rezulte:

Codul scris de mine arata asa:
  1.  
  2. void QS(unsigned short stanga, unsigned short dreapta)
  3. {
  4.     unsigned short i, j, aux, m;
  5.     i=stanga;
  6.     j=dreapta;
  7.     m=mijloc[stanga+(dreapta-stanga)/2].x;
  8.     //folosesc o structura mijloc
  9.     while(i<=j)
  10.     {
  11.         while(mijloc[i].x<m)
  12.             i++;
  13.         while(mijloc[j].x>m)
  14.             j--;
  15.        
  16.         if(i<=j)
  17.         {
  18.             aux = mijloc[i].x;
  19.             mijloc[i].x = mijloc[j].x;
  20.             mijloc[j].x = aux;
  21.             aux = mijloc[i].y;
  22.             mijloc[i].y = mijloc[j].y;
  23.             mijloc[j].y = aux;
  24.             i++;
  25.             j--;
  26.         }
  27.     }
  28.    
  29.     if(stanga<j)
  30.         QS(stanga, j);
  31.    
  32.     if(i<dreapta)
  33.         QS(i,dreapta);
  34. }
  35.  

Folosesc in cadrul programului o structura numita mijloc pentru coordonatele mijlocului unui segment (mijloc[i].x si mijloc[i].y reprezinta coordonatele mijocului segmentului i)


L.E. (-- 06 Aug 2011, 12:36 --)

Am gasit o rezolvare la problema mea(mai neortodoxa...dar functioneaza) ..dupa ce am ordonat cu QS toate coordonatele in functie de x am folosit un QS pentru a ordona toate secventele cu x-ul egal in functie de y. :) Dar totusi ma intereseaza cum as putea sa fac sa le ordonez intr-un singur QS...
0,0p / 0 votes
The EARTH without ART is just EH.
User avatar
cata45
Byte
 
Joined: 02 Sep 2010
Status: 9

Re: Quicksort

Postby eni4ever » 09 Aug 2011, 10:12

^ Două operațiuni de sortare reprezintă o soluție foarte ineficientă dpdv al timpului de execuție. Ai putea încerca o abordare ce presupune o preprocesare apriori a vectorului de elemente.
Considerăm că un element (punct) are următoarea structură:
  1. struct element{
  2.   int pondere;
  3.   char x[10];
  4.   char y[10];
  5. };
unde cel mai important câmp ar fi ponderea. Aceasta am încărca-o din următoarea observație :
Fie
  1. element1.x element1.y
  2. element2.x element2.y
  3. ...
  4. elementn.x elementn.y
rezultatul final al operațiunii de sortare și cu avem unde cu s-a notat concatenarea numerică (ponderea) celor 2 dimensiuni.
Datorită naturii numerice a celor 2 dimensiuni, ponderea ar deveni o valoare algebrică calculată din expresia : . Astfel, pentru un element oarecare i, ponderea atribuită devine .
Astfel, noul câmp conferă posibilitatea de a realiza sortarea coordonatelor după o singură dimensiune realizându-se în fond o singură parcurgere a vectorului de elemete.

Să luăm un exemplu practic. Presupunem că datele de intrare ar fi dintr-o plajă extinsă de semne atât pentru x cât și pentru y :
1 2
-3 5
7 -1
10 19
1 7
-1 -2
.Ponderea calculată pentru fiecare punct ar fi :
12
-25
69
1019
17
-12
.Sortarea elementelor după aceste ponderi ar produce următoarea secvență :
-25
-12
12
17
69
1019
, iar maparea lor pe structura de coordonate inițiale ne-ar oferi rezultatul final :
-3 5
-1 -2
1 2
1 7
7 -1
10 19
. Acest rezultat este, după cum se poate observa, întradevăr o sortare dupa x și y a coordonatelor.

Temă :) : Realizează o sortare dupa y și x.

Spor
0,0p / 0 votes
Image

"Rațiunea vine în umbre scurte numite suferințe." Victor Adăscăliței
"Bender: Anything less than immortality is a complete waste of time.
Zoidberg: Then suicide it is! Step into my office ..." Futurama S06E06
User avatar
eni4ever
DWord
 
Joined: 03 Jan 2010
Location: Timișoara
Status: 57.83

Re: Quicksort

Postby cata45 » 09 Aug 2011, 13:45

Multumes mult de raspuns. Ma gandisem la o concatenare dar ma incurcau mult semnele. Oricum se incadra in timp si solutia mea cu doua sortari (sunt constient ca asta e mult mai buna ...dar la momentul ala trebuia sa fac ceva) Ty again.

Sortare dupa y si x:
  1.  
  2. //#include<fstream>
  3. #include<iostream>
  4. using namespace std;
  5. /*
  6. #define IN "pondere.in"
  7. #define OUT "pondere.out"
  8. fstream f(IN, ios::in), g(OUT, ios::out);
  9. */
  10. int i, n;
  11. struct A{
  12.     long long pondere;
  13.     int x;
  14.     int y;
  15. }point[1000];
  16. int nrcifre(int x)
  17. {
  18.     int nr=0;
  19.     while(x)
  20.     {
  21.         x=x/10;
  22.         nr++;
  23.     }
  24.     return nr;
  25. }
  26. int power(int a)
  27. {
  28.     int i;
  29.     long long result=1;
  30.     for(i=1; i<=a; i++)
  31.         result*=10;
  32.     return result;
  33. }
  34. void QS(int stanga, int dreapta)
  35. {
  36.     int i, j, aux, mijloc;
  37.     i=stanga;
  38.     j=dreapta;
  39.     mijloc=point[stanga+(dreapta-stanga)/2].pondere;
  40.     while(i<=j)
  41.     {
  42.         while(point[i].pondere<mijloc)
  43.             i++;
  44.         while(point[j].pondere>mijloc)
  45.             j--;
  46.         if(i<=j)
  47.         {
  48.             aux=point[i].pondere;
  49.             point[i].pondere=point[j].pondere;
  50.             point[j].pondere=aux;
  51.            
  52.             aux=point[i].x;
  53.             point[i].x=point[j].x;
  54.             point[j].x=aux;
  55.            
  56.             aux=point[i].y;
  57.             point[i].y=point[j].y;
  58.             point[j].y=aux;
  59.            
  60.             i++;
  61.             j--;
  62.         }
  63.     }
  64.     if(stanga<j)
  65.         QS(stanga, j);
  66.     if(dreapta>i)
  67.         QS(i, dreapta);
  68. }
  69. int main()
  70. {
  71.     //f>>n;
  72.     cout<<"n="; cin>>n;
  73.     for(i=1; i<=n; i++)
  74.     {
  75.         //f>>point[i].x>>point[i].y;
  76.         cout<<"Coordonate punct "<<i<<" sub forma x y: ";
  77.         cin>>point[i].x>>point[i].y;
  78.         point[i].pondere=point[i].y*power(nrcifre(point[i].x))+point[i].x;
  79.     }
  80.    
  81.     QS(1,n);
  82.    
  83.     cout<<"\n\nORDONARE DUPA Y\n";
  84.     cout<<"===============================================\n";
  85.     for(i=1; i<=n; i++)
  86.         //g<<point[i].x<<" "<<point[i].y<<" "<<point[i].pondere<<'\n';
  87.         cout<<point[i].x<<" "<<point[i].y<<"\n";
  88. }
  89.    
  90.  

Merge pe coordonate mai "mititele". Pentru coordonate care se apropie de 264este necesar sa folosesc siruri de caractere. Le concatenez si pentru ordonare folosesc strcmp(sirA,sirB); Multumesc inca o data de idee. %%-
0,0p / 0 votes
The EARTH without ART is just EH.
User avatar
cata45
Byte
 
Joined: 02 Sep 2010
Status: 9

Re: Quicksort

Postby morpheus » 10 Aug 2011, 12:33

Nu e bine ce faci. Nu respecti un principiu de baza al designului software, care spune sa separi ceea ce difera de ceea ce ramane la fel.
Ceea ce ramane la fel este logica algoritmului. Ceea ce difera e natura datelor de intrare (ce se vor sortate) si criteriul de comparatie intre elemente apartinand datele de intrare.
Mai precis, algoritmul de sortare ar trebui sa indeplineasca doua conditii:
1. sa nu depinda de tipul datelor de intrare. Initial, algoritmul sorta array-uri de numere intregi. Tu l-ai rescris sa sorteze structuri de tip A. Nu e bine ca l-ai rescris, trebuia sa fie suficient de flexibil ca sa nu depinda de tipul datelor.
2. sa nu depinda de criteriul de comparatie
Tu ai rescris algoritmul folosind un criteriu de comparatie (dubios), hardcoded in mijlocul algoritmului. Solutia uzuala este sa folosesti un pointer la functie (in C) sau un functor (in c++).
Uita-te la prototipul functiei qsort si la algoritmii sort din STL.

Solutia normala, in C++:
1. Algoritmul sa opereze pe o secventa de elemente, specificata cu ajutorul a doi iteratori (de inceput si de sfarsit).
Tipul iteratorului este generic, specificat printr-un parametru template. Astfel decuplezi logica algortimului de tipul concret de date pe care opereaza
2. Algoritmul sa abstractizeze comparatia elementelor folosind un functor (tot ca parametru template)
Astfel abstractizezi criteriul de comparatie intre elementele secventei, ce va fi folosit in procesul de sortare.

Ceva de genul:

  1.  
  2. #include <iostream>
  3. #include <algorithm>
  4. #include <iterator>
  5. #include <functional>
  6.  
  7. template<typename RandomAccessIterator, typename StrictWeakOrdering>
  8. inline RandomAccessIterator ChoosePivot(RandomAccessIterator begin,
  9.     RandomAccessIterator end,
  10.     StrictWeakOrdering comp)
  11. {
  12.     RandomAccessIterator pivot(begin + std::distance(begin, end) / 2);
  13.     if(!comp(*pivot, *begin) && !comp(*begin, *(end - 1)))
  14.         pivot = begin;
  15.     else if(!comp(*pivot, *(end-1)) && !comp(*(end - 1), *begin))
  16.         pivot = end - 1;
  17.     return pivot;
  18. }
  19.  
  20. template<typename RandomAccessIterator, typename StrictWeakOrdering>
  21. RandomAccessIterator Partition(RandomAccessIterator begin,
  22.     RandomAccessIterator end,
  23.     StrictWeakOrdering comp)
  24. {
  25.     RandomAccessIterator pivot = ChoosePivot(begin, end, comp);
  26.     typename std::iterator_traits<RandomAccessIterator>::value_type pivotValue(*pivot);
  27.     std::iter_swap(pivot, end-1);
  28.     RandomAccessIterator store = begin;
  29.     for(RandomAccessIterator it = begin; it != end - 1; ++it) {
  30.         if(!comp(pivotValue, *it)) {
  31.             std::iter_swap(store, it);
  32.             ++store;
  33.         }
  34.     }
  35.     std::iter_swap(end - 1, store);
  36.     return store;
  37. }
  38.  
  39. template<typename RandomAccessIterator, typename StrictWeakOrdering>
  40. void QuickSort(RandomAccessIterator begin,
  41.     RandomAccessIterator end,
  42.     StrictWeakOrdering comp)
  43. {
  44.     if((end - begin) > 1) {
  45.         RandomAccessIterator pivot = Partition(begin, end, comp);
  46.         QuickSort(begin, pivot, comp);
  47.         QuickSort(pivot + 1, end, comp);
  48.     }
  49. }
  50.  
  51. struct Interval
  52. {
  53.     int x;
  54.     int y;
  55. };
  56.  
  57. struct Comparator : public std::binary_function<Interval, Interval, bool>
  58. {
  59.     bool operator() (const Interval& a, const Interval& b)
  60.     {
  61.         if (a.x != b.x)
  62.             return a.x < b.x;
  63.         else
  64.             return a.y < b.y;
  65.     }
  66. };
  67.  
  68. void PrintIntervalsArray(Interval intervals[], size_t count)
  69. {
  70.     for (size_t i = 0; i < count; ++i)
  71.         std::cout << "x=" << intervals[i].x << ",y=" << intervals[i].y << "\n";
  72. }
  73.  
  74. int main()
  75. {
  76.     Interval intervals[] =
  77.     {
  78.         {1, 2},
  79.         {-3, 5},
  80.         {7, -1},
  81.         {10, 19},
  82.         {1, 7},
  83.         {-1, -2},
  84.         {-3, 6},
  85.         {9, 2},
  86.         {10, 1},
  87.         {9, 1},
  88.         {8, 6}
  89.     };
  90.     const size_t intervalsCount = sizeof(intervals) / sizeof(Interval);
  91.     std::cout << "Before sorting \n";
  92.     PrintIntervalsArray(intervals, intervalsCount);
  93.     QuickSort(intervals, intervals + intervalsCount, Comparator());
  94.     std::cout << "After sorting \n";
  95.     PrintIntervalsArray(intervals, intervalsCount);
  96.    
  97.     int arr[] = {9,7,1,5,8,9,3,10,0,0,1,0,1,3,4};
  98.     const size_t arrCount = sizeof(arr) / sizeof(int);
  99.     std::cout << "Before sorting \n";
  100.     std::copy(arr, arr + arrCount, std::ostream_iterator<int>(std::cout, " "));
  101.     std::cout << "\n";
  102.     QuickSort(arr, arr + arrCount, std::less<int>());
  103.     std::cout << "After sorting \n";
  104.     std::copy(arr, arr + arrCount, std::ostream_iterator<int>(std::cout, " "));
  105.     std::cout << "\n";
  106.    
  107.     return 0;
  108. }
  109.  


Poti incerca, ca si exercititu, o implementare C, in care abstractizezi tipul datelor de intrare folosind pointeri la void si criteriul de comparatie folosind un pointer la functie.
0,0p / 0 votes
User avatar
morpheus
Word
 
Joined: 30 Dec 2009
Location: Bucharest, Romania
Status: 54.84


Return to Tutoriale

Who is online

Users browsing this forum: No registered users and 0 guests