Introducere în numărarea sortului

Numărarea Sortare este un algoritm de sortare non-comparson care excelează atunci când sortarea numerelor întregi pe o gamă mică, cunoscută. Spre deosebire de comparare-based-un fel, cum ar fi Quicksort sau Mergesort, care se bazează pe comparații de elemente pereche, Numărare Sortare determină ordinea sortate prin numărarea frecvenței fiecărei valori distincte. Această abordare produce complexitatea timpului liniar în condiții favorabile, făcând-o o alegere pentru multe aplicații critice de performanță în cazul în care domeniul de intrare este limitat.

Algoritmul a fost descris pentru prima dată de Harold H. Seward în 1954 și rămâne o tehnică fundamentală în știința calculatoarelor. Simplitatea și eficiența sa îl fac ideal pentru sarcini precum sortarea vârstelor studenților, a notelor sau a oricăror date întregi cu o răspândire modestă. Prin pârghie de stocare auxiliară proporțională cu intervalul de valori, Numbering Sortare evită O(n log n) limita inferioară de comparare, atingerea timpului O(n + k) unde k este gama de valori de intrare.

Cum se numără lucrări de sortare

Mecanismul de bază al Numărării Sortare este simplu: contează de câte ori apare fiecare valoare în matricea de intrare, apoi folosește care contează pentru a calcula poziția finală a fiecărui element. Procesul constă din trei faze distincte:

  1. Counting: Creați o gamă de numere de mărime k (intervalul de valori de intrare), inițializate la zero. Iterați prin matricea de intrare și incrementați numărul pentru fiecare valoare.
  2. Prefixe de calcul:[ Transformați matricea de numărare într-un array de sumă prefix, în cazul în care fiecare element la index i deține numărul cumulativ de elemente mai mic sau egal cu i. Această etapă determină pozițiile de pornire pentru fiecare valoare distinctă în ieșirea sortate.
  3. Elemente de punere:[ Traversați matricea de intrare de la dreapta la stânga (pentru stabilitate), utilizați matricea de numărare pentru a găsi indexul corect în matricea de ieșire, plasați elementul acolo, și decrementați numărul. Ieșirea finală este o copie sortată a intrării.

Algoritmul returnează un nou array sortate, lăsând originalul neschimbat. O variantă numită în loc Numărare Sortare există, dar este rar utilizată pentru că compromite stabilitatea sau eficiența spațială.

Exemplu pas cu pas

Se analizează sortarea array-ului [4, 2, 8, 3, 1] unde valorile variază între 0 și 8.

  1. Număr:[ Mărimea array-ului de numărare 9 (0
  2. Sumele prefixe: Transformați în cumulative → [0,1,3,5,6,6,6,7]. Acum fiecare valoare ne spune poziția de pornire pentru acel număr în producția sortate.
  3. Reducere:[ Traversare matrice originală de la capăt: primul element citit este 1 → poziție = număr[1] - 1 = 0 → ieșire[0]=1, număr de decrement[1] la 0. Următorul este 3 → poziție = număr[3] - 1 = 4 → ieșire[4]=3, număr[3]=4. Continuați până la toate elementele plasate.

Acest exemplu demonstrează cum se evită în întregime comparaţiile, bazându-se numai pe operaţiuni aritmetice.

Complexitate computerizată

Complexitatea temporală

  • Cel mai bun, mediu și cel mai rău caz: O(n + k), unde n este numărul de elemente și k este gama de valori de intrare. Când k este mic față de n, algoritmul rulează în timp liniar.
  • Comparison to comparison to company sort sort: Quicksort and Mergesort have O(n log n) mediodic comparison. For n = 106 and k = 1000, Counting Sorting (2012 1,001.000 operations) is about 13 times than a tipic O(n log n) sort sort.

Complexitatea spaţială

  • Primar: O(k) pentru matricea de numărare, plus O(n) pentru matricea de ieșire. Această memorie poate fi prohibitivă dacă k este mare (de exemplu, sortarea numerelor întregi de 32 biți unde k = 232).
  • Varianta stabilă: necesită o gamă auxiliară de ieșire de dimensiune n; variantele interne sacrifică stabilitatea sau folosesc manipularea complexă a indicelui.

Când să utilizați sortare numărare

Numărarea Sortare este cea mai eficientă în următoarele condiții:

  • Intrările constau în numere întregi (sau date care pot fi cartografiate într-o gamă mică de numere întregi, cum ar fi caractere sau categorii discrete).
  • Gama k nu este semnificativ mai mare decât n. O regulă comună a degetului mare este k ≤ O(n).
  • Memoria nu este sever constrânsă, deoarece matricea de numărare și tamponul de ieșire necesită spațiu suplimentar.
  • Stabilitatea este necesară (de exemplu, sortarea prin mai multe chei). Implementarea standard este stabilă atunci când elementele sunt plasate de la dreapta la stânga.

Cazurile de utilizare excelentă includ sortarea de clase (0

Limitări şi consideraţii

În ciuda vitezei sale, Numbering Sorting are dezavantaje care limitează aplicabilitatea sa:

  • Numai Integer: Nu poate sorta direct numere sau șiruri de caractere cu puncte plutitoare decât dacă sunt convertite într-un set întreg contiguu.
  • Gama mare: Dacă k pitici n
  • Neadaptativ: Numărarea Sortare necesită întotdeauna scanarea întregului input și construirea matricei de numărare, chiar dacă datele sunt deja sortate sau aproape sortate.
  • Valori negative: Standard Numărare Sortare presupune numere întregi non-negative. Pentru a manipula negative, puteți schimba valorile prin scăderea minimă (facând intervalul 0 la max

Aceste limitări înseamnă Numărare Sortare este un instrument specializat, nu un înlocuitor universal pentru algoritmi de uz general.

Comparație cu algoritmii de sortare asociați

Numărare Sort vs. Radix Sortare

Radix Sortare extinde ideea prin sortarea de cifre de la cel mai puțin semnificative la cele mai semnificative, folosind un tip stabil (de multe ori Sort de numărare) la fiecare cifră. În timp ce Numărarea Sortare funcționează pe o trecere de-a lungul întregului interval k, Radix Sortează efectuează mai multe treceri peste o gamă de cifre mai mică (de exemplu, baza 256), reducerea utilizării memoriei pentru k mare. De exemplu, sortarea numerelor de 32 biți cu Numărare Sortare ar necesita o serie de intrări 232, în timp ce Radix Sortează cu cifre de 8 biți necesită 256 intrări pe trecere și doar patru treceri.

Numărare Sort vs. Bucket Sortare

Bucket Sortare distribuie elemente într-un număr de găleți și sortează fiecare găleată individual (deseori cu inserție de sortat). Numărarea Sort poate fi privită ca un caz special de Bucket Sortare în cazul în care fiecare găleată corespunde unei singure valori distincte. Bucket Sortare funcționează bine pe date uniform distribuite cu puncte plutitoare, dar Numărarea Sort este limitată la domenii întregi.

Implementarea unui sort stabil de numărare

Stabilitatea este importantă atunci când sortarea cu o cheie, păstrând în același timp ordinea relativă a elementelor egale dintr-o altă cheie. Algoritmul standard de numărare Sortare este stabil în mod inerent atunci când bucla de plasare de ieșire traversează intrarea de la dreapta la stânga. Iată o schiță textuală a variantei stabile:

  1. Calculează matricea de numărare după cum este descris.
  2. Conversia la sume prefixe (pozitii ale fiecarei valori in productia sortata).
  3. Iterează matricea de intrare în ordine inversă. Pentru fiecare element, pune-l în poziția indicată de numărul său, apoi decrement care contează.

Pentru că procesăm elemente de la sfârşit, ultima apariţie a unei valori date intră în cel mai înalt indice posibil, păstrând ordinea relativă. Această versiune stabilă este esenţială pentru ca Radix Sortare să funcţioneze corect pe fiecare cifră.

Aplicații practice

  • Sisteme de clasificare educaţională: Sortarea sutelor de scoruri de examen (interval 0
  • Bioinformatică:Sortarea numerelor întregi de citire sau a frecvențelor de k-mer ADN atunci când dimensiunea alfabetului este mică (A, C, G, T).
  • Menținerea indicelui de bază de date: Sortarea identificatorilor unici întregi în intervalul suficient de mici pentru a se potrivi în memorie.
  • Procesare imagine: Sortarea cosurilor histograme sau a grosimilor de culoare (0
  • Sortarea prin cheie secundară: Utilizată în interiorul Radix Sortare, care este calul de lucru pentru sortare eficientă în multe biblioteci și limbi (de exemplu, .NET runtime folosește un amestec adaptativ de algoritmi, inclusiv Numărarea Sortare pentru intervale mici).

Pentru mai multe despre teorie și variante, consultați referințele autoritare, cum ar fi Wikipedia: Numărare Sortare și GeeksforGeeks: Numărare Sortare. Comparații practice cu alți algoritmi pot fi găsite în Brilliants Numărare Sorting article.

Optimizarea sortului de numărare pentru distanțe mari

Când k este mare, dar n este, de asemenea, mare, pur Numărare Sortare devine memorie-intensivă. Există mai multe optimizări:

  • Scurtețe comprimată: Utilizați o hartă hash în loc de un array contiguu atunci când gama de valori utilizate este mare, dar numărul de valori distincte este mic.Acest lucru face schimb de indexare constantă-timp pentru hashing deasupra capului, dar reduce consumul de memorie.
  • Abordări de hibrid: Combinați numărul de ordine Sortează cu alți algoritmi. De exemplu, dacă intervalul depășește 106, utilizați Radix Sortează cu o bază care păstrează intervale de cifre mici.
  • Variante in-place: Unele optimizari reduc spatiul suplimentar la O(k) fara un array de iesire, dar in general sacrifica stabilitatea sau necesita cicluri pentru a localiza pozitiile.

Concluzie

Sortarea de numărare Sortare se remarcă ca un algoritm extrem de eficient pentru sortarea numerelor întregi atunci când gama de valori este mică în raport cu numărul de elemente. Complexitatea sa O (n + k) timp și performanța liniară îl fac indispensabil în scenarii cum ar fi sortarea de grade, Radix Sortare subrutine, și aplicații cu tastele întregi delimitate. Cu toate acestea, algoritmul depinde de intrare în întregime și memoria sa deasupra pentru game mari ne amintește că nici un singur fel este optim pentru toate situațiile. Prin înțelegerea atunci când numărăm exceluri Sortare și Coursera: Numărare Sort Lectură.