Ne dorim:
Radix Sort este un algoritm de sortare care ţine cont de cifre individuale ale elementelor sortate. Aceste elemente pot fi nu doar numere, ci orice altceva ce se poate reprezenta prin întregi. Majoritatea calculatoarelor digitale reprezintă datele în memorie sub formă de numere binare, astfel că procesarea cifrelor din această reprezentare se dovedeşte a fi cea mai convenabilă. Există două tipuri de astfel de sortare: LSD (least significant digit) şi MSD (most significant digit). LSD procesează reprezentările dinspre cea mai puţin semnificativă cifră spre cea mai semnificativă, iar MSD invers.
O versiune simplă a radix sort este cea care foloseşte 10 cozi (câte una pentru fiecare cifră de la 0 la 9). Aceste cozi vor reţine la fiecare pas numerele care au cifra corespunzătoare rangului curent. După această împărţire, elementele se scot din cozi în ordinea crescătoare a indicelui cozii (de la 0 la 9), şi se reţin într-un vector (care devine noua secvenţă de sortat). Exemplu:
Secvenţa iniţială:
170, 45, 75, 90, 2, 24, 802, 66
Numere sunt introduse în 10 cozi (într-un vector de 10 cozi), în funcţie de cifrele de la dreapta la stânga fiecărui număr.
Cozile pentru prima iteraţie vor fi:
* 0: 170, 090 * 1: nimic * 2: 002, 802 * 3: nimic * 4: 024 * 5: 045, 075 * 6: 066 * 7 - 9: nimic
a. Se face dequeue pe toate cozile, în ordinea crescătoare a indexului cozii, şi se pun numerele într-un vector, în ordinea astfel obţinută:
Noua secvenţă de sortat:
170, 090, 002, 802, 024, 045, 075, 066
b. A doua iteraţie:
Cozi:
* 0: 002, 802 * 1: nimic * 2: 024 * 3: nimic * 4: 045 * 5: nimic * 6: 066 * 7: 170, 075 * 8: nimic * 9: 090
Noua secvenţă:
002, 802, 024, 045, 066, 170, 075, 090
c. A treia iteraţie:
Cozi:
* 0: 002, 024, 045, 066, 075, 090 * 1: 170 * 2 - 7: nimic * 8: 802 * 9: nimic
Noua secvenţă:
002, 024, 045, 066, 075, 090, 170, 802 (sortată)
O posibila implementare pentru algoritmul Radix Sort, varianta LSD folosind 10 cozi poate fi urmatoare.
void radixSort(std::vector<int> &v) { // la pasul k Q[i] ca contine toate numerele care au cifra // de pe pozita k egala cu i std::queue<int> Q[10]; // obtine numarul de pasi (este dat de numarul cu cele mai multe cifre) int steps = countDigits ( getMaxValue(v) ); // la fiecare pas ne va interesa un anumit rang (cifra) care // corespunde unei puteri a lui 10 int power = 1; for (int k = 1; k <= steps; ++k) { // fiecare element din v va fi distribuit intr-o coada cu un anumit indice i // corespunzator cifrei de pe pozitia k for (std::vector<int>::iterator it = v.begin(); it != v.end(); ++it) { int i = (*it / power) % 10; // preproceseaza indexul i Q[i].push(*it); // adauga elementul in coada cu numarul i } // pregateste pasul urmator power *= 10; // trec la urmatorul rang // renunt la vechea ordine din v // reconstruiesc v cu ordinea curenta din cozi int n; // numarul curent de elemente din v n = 0; // simulez golirea vectorului for (int i = 0; i <= 9; ++i) { // cat timp coada curent are elemente, muta-le in v while (!Q[i].empty()) { v[n++] = Q[i].front(); // salveaza elemenul in v Q[i].pop(); // sterge elementul din Q[i] } } } }
ATENȚIE! Este nevoie de includerea mai multor biblioteci.
#include <iostream> // std::cin #include <queue> // std::queue #include <cmath> // log10
în funcția de mai sus s-au folosit două funcții auxiliare:
* getMaxValue care returnează cel mai mare element dintr-un vector dat; rezultatul returnat de această funcție reprezintă numărul care are cele mai multe cifre, deci numărul de pași pe care îi va executa algoritmul nostru.
int getMaxValue(const std::vector<int> &v) { int result = v[0]; for (int i = 1; i < v.size(); ++i) { result = std::max( result, v[i] ); } return result; }
* countDigits care returnează numărul de cifre al unui număr întreg.
int countDigits(unsigned int n) { return (int) (1 + log10 ((double) n)); }
Vom folosi următorul cod sursă pentru a testa algoritmul implementat.
int main() { int n; // numarul de elemente din vector int x; // variabila temporara std::vector<int> v; // vectorul care va fi sortat // citire std::cout << "n = "; std::cin >> n; for (int i = 0; i < n; ++i) { // citeste inca un element std::cout << "v[" << i << "] = "; std::cin >> x; // adauga-l in vector v.push_back(x); } // sorteaza radixSort(v); // afiseaza vectorul sortat std::cout << "Dupa sortare:\n"; for (int i = 0; i < n; ++i) { std::cout << v[i] << ' '; } std::cout << "\n"; return 0; }
Compilare
g++ main.cpp -o main
Exemple:
./main n = 5 v[0] = 55 v[1] = 25 v[2] = 43 v[3] = 32 v[4] = 11 Dupa pasul 1 11 32 43 55 25 Dupa pasul 2 11 25 32 43 55 Dupa sortare: 11 25 32 43 55
./main n = 10 v[0] = 123456 v[1] = 134789 v[2] = 198555 v[3] = 223456 v[4] = 111111 v[5] = 222222 v[6] = 923456 v[7] = 111555 v[8] = 999111 v[9] = 123456 Dupa pasul 1 111111 999111 222222 198555 111555 123456 223456 923456 123456 134789 Dupa pasul 2 111111 999111 222222 198555 111555 123456 223456 923456 123456 134789 Dupa pasul 3 111111 999111 222222 123456 223456 923456 123456 198555 111555 134789 Dupa pasul 4 111111 111555 222222 123456 223456 923456 123456 134789 198555 999111 Dupa pasul 5 111111 111555 222222 123456 223456 923456 123456 134789 198555 999111 Dupa pasul 6 111111 111555 123456 123456 134789 198555 222222 223456 923456 999111 Dupa sortare: 111111 111555 123456 123456 134789 198555 222222 223456 923456 999111