Menu
Coddy logo textTech

Counting sort

Ultimo aggiornamento

Il counting sort è un ordinamento non basato sui confronti per numeri interi in un intervallo noto e limitato. Conta quante volte compare ogni valore, poi usa questi conteggi per scrivere ogni valore direttamente nella sua posizione ordinata, senza bisogno di confronti. Premi play qui sopra per vedere i valori contati e poi rimessi in ordine.

Il counting sort richiede tempo O(n + k), dove k è l'intervallo dei valori in ingresso. Quando k non è molto più grande di n è estremamente veloce e può battere gli ordinamenti per confronto O(n log n), ma se l'intervallo dei valori è enorme l'array dei conteggi O(k) lo rende poco pratico.

Complessità temporale e spaziale

CasoComplessitàNote
TempoO(n + k)n elementi, k = intervallo dei valori
SpazioO(n + k)Array dei conteggi + array di output
StabileSìSe si colloca da destra a sinistra usando le somme prefisse
Per confronto?NoOrdina contando, non confrontando
Ideale perPiccolo intervallo di interik vicino a n

Passo dopo passo

PassoCosa succede
1Trova il valore massimo per dimensionare l'array dei conteggi.
2Conta quante volte compare ogni valore.
3(Facoltativo) Trasforma i conteggi in somme prefisse per la stabilità.
4Scrivi ogni valore nell'output tante volte quante compare.
5Ora l'array di output è completamente ordinato.

Esempio svolto

Ordinamento di [1, 4, 1, 2, 4] (i valori vanno da 0 a 4, quindi l'array dei conteggi ha 5 posizioni):

PassataStatoAzione
Scansione inputcount = [0, 2, 1, 0, 2]Conta le occorrenze: 1 compare due volte, 2 una volta, 4 due volte.
Somme prefissecount = [0, 2, 3, 3, 5]Ogni posizione ora contiene quanti valori sono <= al suo indice, e questo dà le posizioni finali.
Colloca 4output = [_, _, _, _, 4]Leggi da destra a sinistra: count[4] = 5, quindi 4 va all'indice 4; decrementa a 4.
Colloca 2output = [_, _, 2, _, 4]count[2] = 3, quindi 2 va all'indice 2; decrementa a 2.
Colloca 1output = [_, 1, 2, _, 4]count[1] = 2, quindi 1 va all'indice 1; decrementa a 1.
Colloca 4output = [_, 1, 2, 4, 4]count[4] = 4, quindi questo 4 va all'indice 3; decrementa a 3.
Colloca 1output = [1, 1, 2, 4, 4]count[1] = 1, quindi questo 1 va all'indice 0. L'array è ordinato.

Quando usare il counting sort

Usalo quandoEvitalo quando
Ordini interi (o chiavi riconducibili a interi) in un intervallo piccolo e noto.L'intervallo dei valori k è molto più grande del numero di elementi n.
Ti serve un tempo lineare O(n + k) e puoi permetterti gli array extra.La memoria è poca: l'array dei conteggi costa O(k) indipendentemente da n.
Ti serve un ordinamento stabile come sottoprocedura (ad es. dentro il radix sort).Le chiavi sono float, stringhe o oggetti arbitrari senza corrispondenza con gli interi.
Il valore massimo è limitato e facile da calcolare in anticipo.L'intervallo è sconosciuto o illimitato, quindi non puoi dimensionare l'array dei conteggi.

Codice Counting Sort

Un'implementazione di Counting Sort pulita ed eseguibile in Python, JavaScript, Java, C++, C. Scegli un linguaggio, copia il codice o aprilo già caricato nel Playground di Coddy.

Codice Counting Sort in Python

Python
1def counting_sort(a):2    # Works for non-negative integers with a small max value3    counts = [0] * (max(a) + 1)4    for value in a:5        counts[value] += 16    # Prefix sums turn counts into final positions7    for i in range(1, len(counts)):8        counts[i] += counts[i - 1]9    out = [0] * len(a)10    for value in reversed(a):  # reversed keeps equal values stable11        counts[value] -= 112        out[counts[value]] = value13    return out14
15
16nums = [4, 2, 2, 8, 3, 3, 1]17print("Before:", nums)18print("After: ", counting_sort(nums))
Esegui questo codice nel playground Python

Domande frequenti sul counting sort

Qual è la complessità temporale del counting sort?
Il counting sort è O(n + k), dove n è il numero di elementi e k l'intervallo dei valori possibili. Quando k = O(n) il tempo è lineare. Usa O(n + k) di spazio extra.
Il counting sort è stabile?
Può esserlo. La versione stabile costruisce le somme prefisse dei conteggi e colloca gli elementi da destra a sinistra, preservando l'ordine relativo delle chiavi uguali. La versione semplice "riscrivi per valore" mostrata qui produce un ordinamento corretto ma si usa soprattutto per interi semplici.
Quando conviene usare il counting sort?
Usalo quando ordini interi (o chiavi riconducibili a interi) in un intervallo piccolo e noto. Se l'intervallo dei valori k è molto più grande del numero di elementi, l'array dei conteggi spreca memoria ed è meglio un ordinamento per confronto.
Qual è la differenza tra counting sort e radix sort?
Il counting sort ordina in base al valore intero in una sola passata e ha bisogno di un array dei conteggi grande quanto l'intervallo dei valori. Il radix sort ordina cifra per cifra e di solito usa un counting sort stabile su ogni cifra, così l'intervallo per passata resta piccolo (ad es. 10 per le cifre decimali). Il radix sort gestisce grandi intervalli di valori che renderebbero poco pratico un singolo counting sort.
Perché il counting sort non è sempre più veloce del quicksort?
Il counting sort è O(n + k), quindi vince solo quando l'intervallo dei valori k è paragonabile a n. Se k è enorme, per esempio ordinare 100 valori nell'intervallo da 0 a 1,000,000,000, l'array dei conteggi O(k) domina e spreca memoria, mentre un ordinamento per confronto O(n log n) come il quicksort resta veloce ed efficiente in spazio.
Il counting sort gestisce i numeri negativi?
Sì, con un piccolo scostamento. Invece di indicizzare l'array dei conteggi direttamente con il valore, indicizzalo con value - min, così il valore più piccolo corrisponde all'indice 0. La dimensione dell'array dei conteggi diventa max - min + 1. Dimenticare questo scostamento è un bug comune che manda in crash il programma con input negativi.
Illustrazione dei linguaggi di programmazione di Coddy

Padroneggia gli algoritmi con Coddy

INIZIA